LCOV - code coverage report
Current view: top level - lib/matrix_api_lite/generated - api.dart (source / functions) Hit Total Coverage
Test: merged.info Lines: 598 1854 32.3 %
Date: 2024-07-12 20:20:16 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:convert';
       2             : import 'dart:typed_data';
       3             : 
       4             : import 'package:http/http.dart';
       5             : 
       6             : import 'package:matrix/matrix_api_lite/generated/fixed_model.dart';
       7             : import 'package:matrix/matrix_api_lite/generated/internal.dart';
       8             : import 'package:matrix/matrix_api_lite/generated/model.dart';
       9             : import 'package:matrix/matrix_api_lite/model/auth/authentication_data.dart';
      10             : import 'package:matrix/matrix_api_lite/model/auth/authentication_identifier.dart';
      11             : import 'package:matrix/matrix_api_lite/model/matrix_event.dart';
      12             : import 'package:matrix/matrix_api_lite/model/matrix_keys.dart';
      13             : import 'package:matrix/matrix_api_lite/model/sync_update.dart';
      14             : 
      15             : class Api {
      16             :   Client httpClient;
      17             :   Uri? baseUri;
      18             :   String? bearerToken;
      19          38 :   Api({Client? httpClient, this.baseUri, this.bearerToken})
      20           0 :       : httpClient = httpClient ?? Client();
      21           1 :   Never unexpectedResponse(BaseResponse response, Uint8List body) {
      22           1 :     throw Exception('http error response');
      23             :   }
      24             : 
      25           0 :   Never bodySizeExceeded(int expected, int actual) {
      26           0 :     throw Exception('body size $actual exceeded $expected');
      27             :   }
      28             : 
      29             :   /// Gets discovery information about the domain. The file may include
      30             :   /// additional keys, which MUST follow the Java package naming convention,
      31             :   /// e.g. `com.example.myapp.property`. This ensures property names are
      32             :   /// suitably namespaced for each application and reduces the risk of
      33             :   /// clashes.
      34             :   ///
      35             :   /// Note that this endpoint is not necessarily handled by the homeserver,
      36             :   /// but by another webserver, to be used for discovering the homeserver URL.
      37           1 :   Future<DiscoveryInformation> getWellknown() async {
      38           1 :     final requestUri = Uri(path: '.well-known/matrix/client');
      39           3 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
      40           2 :     final response = await httpClient.send(request);
      41           2 :     final responseBody = await response.stream.toBytes();
      42           3 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
      43           0 :     final responseString = utf8.decode(responseBody);
      44           0 :     final json = jsonDecode(responseString);
      45           0 :     return DiscoveryInformation.fromJson(json as Map<String, Object?>);
      46             :   }
      47             : 
      48             :   /// Queries the server to determine if a given registration token is still
      49             :   /// valid at the time of request. This is a point-in-time check where the
      50             :   /// token might still expire by the time it is used.
      51             :   ///
      52             :   /// Servers should be sure to rate limit this endpoint to avoid brute force
      53             :   /// attacks.
      54             :   ///
      55             :   /// [token] The token to check validity of.
      56             :   ///
      57             :   /// returns `valid`:
      58             :   /// True if the token is still valid, false otherwise. This should
      59             :   /// additionally be false if the token is not a recognised token by
      60             :   /// the server.
      61           0 :   Future<bool> registrationTokenValidity(String token) async {
      62           0 :     final requestUri = Uri(
      63             :         path: '_matrix/client/v1/register/m.login.registration_token/validity',
      64           0 :         queryParameters: {
      65             :           'token': token,
      66             :         });
      67           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
      68           0 :     final response = await httpClient.send(request);
      69           0 :     final responseBody = await response.stream.toBytes();
      70           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
      71           0 :     final responseString = utf8.decode(responseBody);
      72           0 :     final json = jsonDecode(responseString);
      73           0 :     return json['valid'] as bool;
      74             :   }
      75             : 
      76             :   /// Paginates over the space tree in a depth-first manner to locate child rooms of a given space.
      77             :   ///
      78             :   /// Where a child room is unknown to the local server, federation is used to fill in the details.
      79             :   /// The servers listed in the `via` array should be contacted to attempt to fill in missing rooms.
      80             :   ///
      81             :   /// Only [`m.space.child`](#mspacechild) state events of the room are considered. Invalid child
      82             :   /// rooms and parent events are not covered by this endpoint.
      83             :   ///
      84             :   /// [roomId] The room ID of the space to get a hierarchy for.
      85             :   ///
      86             :   /// [suggestedOnly] Optional (default `false`) flag to indicate whether or not the server should only consider
      87             :   /// suggested rooms. Suggested rooms are annotated in their [`m.space.child`](#mspacechild) event
      88             :   /// contents.
      89             :   ///
      90             :   /// [limit] Optional limit for the maximum number of rooms to include per response. Must be an integer
      91             :   /// greater than zero.
      92             :   ///
      93             :   /// Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.
      94             :   ///
      95             :   /// [maxDepth] Optional limit for how far to go into the space. Must be a non-negative integer.
      96             :   ///
      97             :   /// When reached, no further child rooms will be returned.
      98             :   ///
      99             :   /// Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.
     100             :   ///
     101             :   /// [from] A pagination token from a previous result. If specified, `max_depth` and `suggested_only` cannot
     102             :   /// be changed from the first request.
     103           0 :   Future<GetSpaceHierarchyResponse> getSpaceHierarchy(String roomId,
     104             :       {bool? suggestedOnly, int? limit, int? maxDepth, String? from}) async {
     105           0 :     final requestUri = Uri(
     106             :         path:
     107           0 :             '_matrix/client/v1/rooms/${Uri.encodeComponent(roomId)}/hierarchy',
     108           0 :         queryParameters: {
     109           0 :           if (suggestedOnly != null) 'suggested_only': suggestedOnly.toString(),
     110           0 :           if (limit != null) 'limit': limit.toString(),
     111           0 :           if (maxDepth != null) 'max_depth': maxDepth.toString(),
     112           0 :           if (from != null) 'from': from,
     113             :         });
     114           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
     115           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     116           0 :     final response = await httpClient.send(request);
     117           0 :     final responseBody = await response.stream.toBytes();
     118           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     119           0 :     final responseString = utf8.decode(responseBody);
     120           0 :     final json = jsonDecode(responseString);
     121           0 :     return GetSpaceHierarchyResponse.fromJson(json as Map<String, Object?>);
     122             :   }
     123             : 
     124             :   /// Retrieve all of the child events for a given parent event.
     125             :   ///
     126             :   /// Note that when paginating the `from` token should be "after" the `to` token in
     127             :   /// terms of topological ordering, because it is only possible to paginate "backwards"
     128             :   /// through events, starting at `from`.
     129             :   ///
     130             :   /// For example, passing a `from` token from page 2 of the results, and a `to` token
     131             :   /// from page 1, would return the empty set. The caller can use a `from` token from
     132             :   /// page 1 and a `to` token from page 2 to paginate over the same range, however.
     133             :   ///
     134             :   /// [roomId] The ID of the room containing the parent event.
     135             :   ///
     136             :   /// [eventId] The ID of the parent event whose child events are to be returned.
     137             :   ///
     138             :   /// [from] The pagination token to start returning results from. If not supplied, results
     139             :   /// start at the most recent topological event known to the server.
     140             :   ///
     141             :   /// Can be a `next_batch` or `prev_batch` token from a previous call, or a returned
     142             :   /// `start` token from [`/messages`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3roomsroomidmessages),
     143             :   /// or a `next_batch` token from [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync).
     144             :   ///
     145             :   /// [to] The pagination token to stop returning results at. If not supplied, results
     146             :   /// continue up to `limit` or until there are no more events.
     147             :   ///
     148             :   /// Like `from`, this can be a previous token from a prior call to this endpoint
     149             :   /// or from `/messages` or `/sync`.
     150             :   ///
     151             :   /// [limit] The maximum number of results to return in a single `chunk`. The server can
     152             :   /// and should apply a maximum value to this parameter to avoid large responses.
     153             :   ///
     154             :   /// Similarly, the server should apply a default value when not supplied.
     155             :   ///
     156             :   /// [dir] Optional (default `b`) direction to return events from. If this is set to `f`, events
     157             :   /// will be returned in chronological order starting at `from`. If it
     158             :   /// is set to `b`, events will be returned in *reverse* chronological
     159             :   /// order, again starting at `from`.
     160           0 :   Future<GetRelatingEventsResponse> getRelatingEvents(
     161             :       String roomId, String eventId,
     162             :       {String? from, String? to, int? limit, Direction? dir}) async {
     163           0 :     final requestUri = Uri(
     164             :         path:
     165           0 :             '_matrix/client/v1/rooms/${Uri.encodeComponent(roomId)}/relations/${Uri.encodeComponent(eventId)}',
     166           0 :         queryParameters: {
     167           0 :           if (from != null) 'from': from,
     168           0 :           if (to != null) 'to': to,
     169           0 :           if (limit != null) 'limit': limit.toString(),
     170           0 :           if (dir != null) 'dir': dir.name,
     171             :         });
     172           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
     173           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     174           0 :     final response = await httpClient.send(request);
     175           0 :     final responseBody = await response.stream.toBytes();
     176           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     177           0 :     final responseString = utf8.decode(responseBody);
     178           0 :     final json = jsonDecode(responseString);
     179           0 :     return GetRelatingEventsResponse.fromJson(json as Map<String, Object?>);
     180             :   }
     181             : 
     182             :   /// Retrieve all of the child events for a given parent event which relate to the parent
     183             :   /// using the given `relType`.
     184             :   ///
     185             :   /// Note that when paginating the `from` token should be "after" the `to` token in
     186             :   /// terms of topological ordering, because it is only possible to paginate "backwards"
     187             :   /// through events, starting at `from`.
     188             :   ///
     189             :   /// For example, passing a `from` token from page 2 of the results, and a `to` token
     190             :   /// from page 1, would return the empty set. The caller can use a `from` token from
     191             :   /// page 1 and a `to` token from page 2 to paginate over the same range, however.
     192             :   ///
     193             :   /// [roomId] The ID of the room containing the parent event.
     194             :   ///
     195             :   /// [eventId] The ID of the parent event whose child events are to be returned.
     196             :   ///
     197             :   /// [relType] The [relationship type](https://spec.matrix.org/unstable/client-server-api/#relationship-types) to search for.
     198             :   ///
     199             :   /// [from] The pagination token to start returning results from. If not supplied, results
     200             :   /// start at the most recent topological event known to the server.
     201             :   ///
     202             :   /// Can be a `next_batch` or `prev_batch` token from a previous call, or a returned
     203             :   /// `start` token from [`/messages`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3roomsroomidmessages),
     204             :   /// or a `next_batch` token from [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync).
     205             :   ///
     206             :   /// [to] The pagination token to stop returning results at. If not supplied, results
     207             :   /// continue up to `limit` or until there are no more events.
     208             :   ///
     209             :   /// Like `from`, this can be a previous token from a prior call to this endpoint
     210             :   /// or from `/messages` or `/sync`.
     211             :   ///
     212             :   /// [limit] The maximum number of results to return in a single `chunk`. The server can
     213             :   /// and should apply a maximum value to this parameter to avoid large responses.
     214             :   ///
     215             :   /// Similarly, the server should apply a default value when not supplied.
     216             :   ///
     217             :   /// [dir] Optional (default `b`) direction to return events from. If this is set to `f`, events
     218             :   /// will be returned in chronological order starting at `from`. If it
     219             :   /// is set to `b`, events will be returned in *reverse* chronological
     220             :   /// order, again starting at `from`.
     221           0 :   Future<GetRelatingEventsWithRelTypeResponse> getRelatingEventsWithRelType(
     222             :       String roomId, String eventId, String relType,
     223             :       {String? from, String? to, int? limit, Direction? dir}) async {
     224           0 :     final requestUri = Uri(
     225             :         path:
     226           0 :             '_matrix/client/v1/rooms/${Uri.encodeComponent(roomId)}/relations/${Uri.encodeComponent(eventId)}/${Uri.encodeComponent(relType)}',
     227           0 :         queryParameters: {
     228           0 :           if (from != null) 'from': from,
     229           0 :           if (to != null) 'to': to,
     230           0 :           if (limit != null) 'limit': limit.toString(),
     231           0 :           if (dir != null) 'dir': dir.name,
     232             :         });
     233           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
     234           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     235           0 :     final response = await httpClient.send(request);
     236           0 :     final responseBody = await response.stream.toBytes();
     237           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     238           0 :     final responseString = utf8.decode(responseBody);
     239           0 :     final json = jsonDecode(responseString);
     240           0 :     return GetRelatingEventsWithRelTypeResponse.fromJson(
     241             :         json as Map<String, Object?>);
     242             :   }
     243             : 
     244             :   /// Retrieve all of the child events for a given parent event which relate to the parent
     245             :   /// using the given `relType` and have the given `eventType`.
     246             :   ///
     247             :   /// Note that when paginating the `from` token should be "after" the `to` token in
     248             :   /// terms of topological ordering, because it is only possible to paginate "backwards"
     249             :   /// through events, starting at `from`.
     250             :   ///
     251             :   /// For example, passing a `from` token from page 2 of the results, and a `to` token
     252             :   /// from page 1, would return the empty set. The caller can use a `from` token from
     253             :   /// page 1 and a `to` token from page 2 to paginate over the same range, however.
     254             :   ///
     255             :   /// [roomId] The ID of the room containing the parent event.
     256             :   ///
     257             :   /// [eventId] The ID of the parent event whose child events are to be returned.
     258             :   ///
     259             :   /// [relType] The [relationship type](https://spec.matrix.org/unstable/client-server-api/#relationship-types) to search for.
     260             :   ///
     261             :   /// [eventType] The event type of child events to search for.
     262             :   ///
     263             :   /// Note that in encrypted rooms this will typically always be `m.room.encrypted`
     264             :   /// regardless of the event type contained within the encrypted payload.
     265             :   ///
     266             :   /// [from] The pagination token to start returning results from. If not supplied, results
     267             :   /// start at the most recent topological event known to the server.
     268             :   ///
     269             :   /// Can be a `next_batch` or `prev_batch` token from a previous call, or a returned
     270             :   /// `start` token from [`/messages`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3roomsroomidmessages),
     271             :   /// or a `next_batch` token from [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync).
     272             :   ///
     273             :   /// [to] The pagination token to stop returning results at. If not supplied, results
     274             :   /// continue up to `limit` or until there are no more events.
     275             :   ///
     276             :   /// Like `from`, this can be a previous token from a prior call to this endpoint
     277             :   /// or from `/messages` or `/sync`.
     278             :   ///
     279             :   /// [limit] The maximum number of results to return in a single `chunk`. The server can
     280             :   /// and should apply a maximum value to this parameter to avoid large responses.
     281             :   ///
     282             :   /// Similarly, the server should apply a default value when not supplied.
     283             :   ///
     284             :   /// [dir] Optional (default `b`) direction to return events from. If this is set to `f`, events
     285             :   /// will be returned in chronological order starting at `from`. If it
     286             :   /// is set to `b`, events will be returned in *reverse* chronological
     287             :   /// order, again starting at `from`.
     288           0 :   Future<GetRelatingEventsWithRelTypeAndEventTypeResponse>
     289             :       getRelatingEventsWithRelTypeAndEventType(
     290             :           String roomId, String eventId, String relType, String eventType,
     291             :           {String? from, String? to, int? limit, Direction? dir}) async {
     292           0 :     final requestUri = Uri(
     293             :         path:
     294           0 :             '_matrix/client/v1/rooms/${Uri.encodeComponent(roomId)}/relations/${Uri.encodeComponent(eventId)}/${Uri.encodeComponent(relType)}/${Uri.encodeComponent(eventType)}',
     295           0 :         queryParameters: {
     296           0 :           if (from != null) 'from': from,
     297           0 :           if (to != null) 'to': to,
     298           0 :           if (limit != null) 'limit': limit.toString(),
     299           0 :           if (dir != null) 'dir': dir.name,
     300             :         });
     301           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
     302           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     303           0 :     final response = await httpClient.send(request);
     304           0 :     final responseBody = await response.stream.toBytes();
     305           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     306           0 :     final responseString = utf8.decode(responseBody);
     307           0 :     final json = jsonDecode(responseString);
     308           0 :     return GetRelatingEventsWithRelTypeAndEventTypeResponse.fromJson(
     309             :         json as Map<String, Object?>);
     310             :   }
     311             : 
     312             :   /// Paginates over the thread roots in a room, ordered by the `latest_event` of each thread root
     313             :   /// in its bundle.
     314             :   ///
     315             :   /// [roomId] The room ID where the thread roots are located.
     316             :   ///
     317             :   /// [include] Optional (default `all`) flag to denote which thread roots are of interest to the caller.
     318             :   /// When `all`, all thread roots found in the room are returned. When `participated`, only
     319             :   /// thread roots for threads the user has [participated in](https://spec.matrix.org/unstable/client-server-api/#server-side-aggregation-of-mthread-relationships)
     320             :   /// will be returned.
     321             :   ///
     322             :   /// [limit] Optional limit for the maximum number of thread roots to include per response. Must be an integer
     323             :   /// greater than zero.
     324             :   ///
     325             :   /// Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.
     326             :   ///
     327             :   /// [from] A pagination token from a previous result. When not provided, the server starts paginating from
     328             :   /// the most recent event visible to the user (as per history visibility rules; topologically).
     329           0 :   Future<GetThreadRootsResponse> getThreadRoots(String roomId,
     330             :       {Include? include, int? limit, String? from}) async {
     331           0 :     final requestUri = Uri(
     332           0 :         path: '_matrix/client/v1/rooms/${Uri.encodeComponent(roomId)}/threads',
     333           0 :         queryParameters: {
     334           0 :           if (include != null) 'include': include.name,
     335           0 :           if (limit != null) 'limit': limit.toString(),
     336           0 :           if (from != null) 'from': from,
     337             :         });
     338           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
     339           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     340           0 :     final response = await httpClient.send(request);
     341           0 :     final responseBody = await response.stream.toBytes();
     342           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     343           0 :     final responseString = utf8.decode(responseBody);
     344           0 :     final json = jsonDecode(responseString);
     345           0 :     return GetThreadRootsResponse.fromJson(json as Map<String, Object?>);
     346             :   }
     347             : 
     348             :   /// Get the ID of the event closest to the given timestamp, in the
     349             :   /// direction specified by the `dir` parameter.
     350             :   ///
     351             :   /// If the server does not have all of the room history and does not have
     352             :   /// an event suitably close to the requested timestamp, it can use the
     353             :   /// corresponding [federation endpoint](https://spec.matrix.org/unstable/server-server-api/#get_matrixfederationv1timestamp_to_eventroomid)
     354             :   /// to ask other servers for a suitable event.
     355             :   ///
     356             :   /// After calling this endpoint, clients can call
     357             :   /// [`/rooms/{roomId}/context/{eventId}`](#get_matrixclientv3roomsroomidcontexteventid)
     358             :   /// to obtain a pagination token to retrieve the events around the returned event.
     359             :   ///
     360             :   /// The event returned by this endpoint could be an event that the client
     361             :   /// cannot render, and so may need to paginate in order to locate an event
     362             :   /// that it can display, which may end up being outside of the client's
     363             :   /// suitable range.  Clients can employ different strategies to display
     364             :   /// something reasonable to the user.  For example, the client could try
     365             :   /// paginating in one direction for a while, while looking at the
     366             :   /// timestamps of the events that it is paginating through, and if it
     367             :   /// exceeds a certain difference from the target timestamp, it can try
     368             :   /// paginating in the opposite direction.  The client could also simply
     369             :   /// paginate in one direction and inform the user that the closest event
     370             :   /// found in that direction is outside of the expected range.
     371             :   ///
     372             :   /// [roomId] The ID of the room to search
     373             :   ///
     374             :   /// [ts] The timestamp to search from, as given in milliseconds
     375             :   /// since the Unix epoch.
     376             :   ///
     377             :   /// [dir] The direction in which to search.  `f` for forwards, `b` for backwards.
     378           0 :   Future<GetEventByTimestampResponse> getEventByTimestamp(
     379             :       String roomId, int ts, Direction dir) async {
     380           0 :     final requestUri = Uri(
     381             :         path:
     382           0 :             '_matrix/client/v1/rooms/${Uri.encodeComponent(roomId)}/timestamp_to_event',
     383           0 :         queryParameters: {
     384           0 :           'ts': ts.toString(),
     385           0 :           'dir': dir.name,
     386             :         });
     387           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
     388           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     389           0 :     final response = await httpClient.send(request);
     390           0 :     final responseBody = await response.stream.toBytes();
     391           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     392           0 :     final responseString = utf8.decode(responseBody);
     393           0 :     final json = jsonDecode(responseString);
     394           0 :     return GetEventByTimestampResponse.fromJson(json as Map<String, Object?>);
     395             :   }
     396             : 
     397             :   /// Gets a list of the third party identifiers that the homeserver has
     398             :   /// associated with the user's account.
     399             :   ///
     400             :   /// This is *not* the same as the list of third party identifiers bound to
     401             :   /// the user's Matrix ID in identity servers.
     402             :   ///
     403             :   /// Identifiers in this list may be used by the homeserver as, for example,
     404             :   /// identifiers that it will accept to reset the user's account password.
     405             :   ///
     406             :   /// returns `threepids`:
     407             :   ///
     408           0 :   Future<List<ThirdPartyIdentifier>?> getAccount3PIDs() async {
     409           0 :     final requestUri = Uri(path: '_matrix/client/v3/account/3pid');
     410           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
     411           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     412           0 :     final response = await httpClient.send(request);
     413           0 :     final responseBody = await response.stream.toBytes();
     414           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     415           0 :     final responseString = utf8.decode(responseBody);
     416           0 :     final json = jsonDecode(responseString);
     417           0 :     return ((v) => v != null
     418             :         ? (v as List)
     419           0 :             .map(
     420           0 :                 (v) => ThirdPartyIdentifier.fromJson(v as Map<String, Object?>))
     421           0 :             .toList()
     422           0 :         : null)(json['threepids']);
     423             :   }
     424             : 
     425             :   /// Adds contact information to the user's account.
     426             :   ///
     427             :   /// This endpoint is deprecated in favour of the more specific `/3pid/add`
     428             :   /// and `/3pid/bind` endpoints.
     429             :   ///
     430             :   /// **Note:**
     431             :   /// Previously this endpoint supported a `bind` parameter. This parameter
     432             :   /// has been removed, making this endpoint behave as though it was `false`.
     433             :   /// This results in this endpoint being an equivalent to `/3pid/bind` rather
     434             :   /// than dual-purpose.
     435             :   ///
     436             :   /// [threePidCreds] The third party credentials to associate with the account.
     437             :   ///
     438             :   /// returns `submit_url`:
     439             :   /// An optional field containing a URL where the client must
     440             :   /// submit the validation token to, with identical parameters
     441             :   /// to the Identity Service API's `POST
     442             :   /// /validate/email/submitToken` endpoint (without the requirement
     443             :   /// for an access token). The homeserver must send this token to the
     444             :   /// user (if applicable), who should then be prompted to provide it
     445             :   /// to the client.
     446             :   ///
     447             :   /// If this field is not present, the client can assume that
     448             :   /// verification will happen without the client's involvement
     449             :   /// provided the homeserver advertises this specification version
     450             :   /// in the `/versions` response (ie: r0.5.0).
     451           0 :   @Deprecated('message')
     452             :   Future<Uri?> post3PIDs(ThreePidCredentials threePidCreds) async {
     453           0 :     final requestUri = Uri(path: '_matrix/client/v3/account/3pid');
     454           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     455           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     456           0 :     request.headers['content-type'] = 'application/json';
     457           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     458           0 :       'three_pid_creds': threePidCreds.toJson(),
     459             :     }));
     460           0 :     final response = await httpClient.send(request);
     461           0 :     final responseBody = await response.stream.toBytes();
     462           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     463           0 :     final responseString = utf8.decode(responseBody);
     464           0 :     final json = jsonDecode(responseString);
     465           0 :     return ((v) =>
     466           0 :         v != null ? Uri.parse(v as String) : null)(json['submit_url']);
     467             :   }
     468             : 
     469             :   /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api).
     470             :   ///
     471             :   /// Adds contact information to the user's account. Homeservers should use 3PIDs added
     472             :   /// through this endpoint for password resets instead of relying on the identity server.
     473             :   ///
     474             :   /// Homeservers should prevent the caller from adding a 3PID to their account if it has
     475             :   /// already been added to another user's account on the homeserver.
     476             :   ///
     477             :   /// [auth] Additional authentication information for the
     478             :   /// user-interactive authentication API.
     479             :   ///
     480             :   /// [clientSecret] The client secret used in the session with the homeserver.
     481             :   ///
     482             :   /// [sid] The session identifier given by the homeserver.
     483           0 :   Future<void> add3PID(String clientSecret, String sid,
     484             :       {AuthenticationData? auth}) async {
     485           0 :     final requestUri = Uri(path: '_matrix/client/v3/account/3pid/add');
     486           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     487           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     488           0 :     request.headers['content-type'] = 'application/json';
     489           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     490           0 :       if (auth != null) 'auth': auth.toJson(),
     491           0 :       'client_secret': clientSecret,
     492           0 :       'sid': sid,
     493             :     }));
     494           0 :     final response = await httpClient.send(request);
     495           0 :     final responseBody = await response.stream.toBytes();
     496           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     497           0 :     final responseString = utf8.decode(responseBody);
     498           0 :     final json = jsonDecode(responseString);
     499           0 :     return ignore(json);
     500             :   }
     501             : 
     502             :   /// Binds a 3PID to the user's account through the specified identity server.
     503             :   ///
     504             :   /// Homeservers should not prevent this request from succeeding if another user
     505             :   /// has bound the 3PID. Homeservers should simply proxy any errors received by
     506             :   /// the identity server to the caller.
     507             :   ///
     508             :   /// Homeservers should track successful binds so they can be unbound later.
     509             :   ///
     510             :   /// [clientSecret] The client secret used in the session with the identity server.
     511             :   ///
     512             :   /// [idAccessToken] An access token previously registered with the identity server.
     513             :   ///
     514             :   /// [idServer] The identity server to use.
     515             :   ///
     516             :   /// [sid] The session identifier given by the identity server.
     517           0 :   Future<void> bind3PID(String clientSecret, String idAccessToken,
     518             :       String idServer, String sid) async {
     519           0 :     final requestUri = Uri(path: '_matrix/client/v3/account/3pid/bind');
     520           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     521           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     522           0 :     request.headers['content-type'] = 'application/json';
     523           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     524             :       'client_secret': clientSecret,
     525             :       'id_access_token': idAccessToken,
     526             :       'id_server': idServer,
     527             :       'sid': sid,
     528             :     }));
     529           0 :     final response = await httpClient.send(request);
     530           0 :     final responseBody = await response.stream.toBytes();
     531           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     532           0 :     final responseString = utf8.decode(responseBody);
     533           0 :     final json = jsonDecode(responseString);
     534           0 :     return ignore(json);
     535             :   }
     536             : 
     537             :   /// Removes a third party identifier from the user's account. This might not
     538             :   /// cause an unbind of the identifier from the identity server.
     539             :   ///
     540             :   /// Unlike other endpoints, this endpoint does not take an `id_access_token`
     541             :   /// parameter because the homeserver is expected to sign the request to the
     542             :   /// identity server instead.
     543             :   ///
     544             :   /// [address] The third party address being removed.
     545             :   ///
     546             :   /// [idServer] The identity server to unbind from. If not provided, the homeserver
     547             :   /// MUST use the `id_server` the identifier was added through. If the
     548             :   /// homeserver does not know the original `id_server`, it MUST return
     549             :   /// a `id_server_unbind_result` of `no-support`.
     550             :   ///
     551             :   /// [medium] The medium of the third party identifier being removed.
     552             :   ///
     553             :   /// returns `id_server_unbind_result`:
     554             :   /// An indicator as to whether or not the homeserver was able to unbind
     555             :   /// the 3PID from the identity server. `success` indicates that the
     556             :   /// identity server has unbound the identifier whereas `no-support`
     557             :   /// indicates that the identity server refuses to support the request
     558             :   /// or the homeserver was not able to determine an identity server to
     559             :   /// unbind from.
     560           0 :   Future<IdServerUnbindResult> delete3pidFromAccount(
     561             :       String address, ThirdPartyIdentifierMedium medium,
     562             :       {String? idServer}) async {
     563           0 :     final requestUri = Uri(path: '_matrix/client/v3/account/3pid/delete');
     564           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     565           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     566           0 :     request.headers['content-type'] = 'application/json';
     567           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     568           0 :       'address': address,
     569           0 :       if (idServer != null) 'id_server': idServer,
     570           0 :       'medium': medium.name,
     571             :     }));
     572           0 :     final response = await httpClient.send(request);
     573           0 :     final responseBody = await response.stream.toBytes();
     574           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     575           0 :     final responseString = utf8.decode(responseBody);
     576           0 :     final json = jsonDecode(responseString);
     577             :     return IdServerUnbindResult.values
     578           0 :         .fromString(json['id_server_unbind_result'] as String)!;
     579             :   }
     580             : 
     581             :   /// The homeserver must check that the given email address is **not**
     582             :   /// already associated with an account on this homeserver. This API should
     583             :   /// be used to request validation tokens when adding an email address to an
     584             :   /// account. This API's parameters and response are identical to that of
     585             :   /// the [`/register/email/requestToken`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv3registeremailrequesttoken)
     586             :   /// endpoint. The homeserver should validate
     587             :   /// the email itself, either by sending a validation email itself or by using
     588             :   /// a service it has control over.
     589             :   ///
     590             :   /// [clientSecret] A unique string generated by the client, and used to identify the
     591             :   /// validation attempt. It must be a string consisting of the characters
     592             :   /// `[0-9a-zA-Z.=_-]`. Its length must not exceed 255 characters and it
     593             :   /// must not be empty.
     594             :   ///
     595             :   ///
     596             :   /// [email] The email address to validate.
     597             :   ///
     598             :   /// [nextLink] Optional. When the validation is completed, the identity server will
     599             :   /// redirect the user to this URL. This option is ignored when submitting
     600             :   /// 3PID validation information through a POST request.
     601             :   ///
     602             :   /// [sendAttempt] The server will only send an email if the `send_attempt`
     603             :   /// is a number greater than the most recent one which it has seen,
     604             :   /// scoped to that `email` + `client_secret` pair. This is to
     605             :   /// avoid repeatedly sending the same email in the case of request
     606             :   /// retries between the POSTing user and the identity server.
     607             :   /// The client should increment this value if they desire a new
     608             :   /// email (e.g. a reminder) to be sent. If they do not, the server
     609             :   /// should respond with success but not resend the email.
     610             :   ///
     611             :   /// [idAccessToken] An access token previously registered with the identity server. Servers
     612             :   /// can treat this as optional to distinguish between r0.5-compatible clients
     613             :   /// and this specification version.
     614             :   ///
     615             :   /// Required if an `id_server` is supplied.
     616             :   ///
     617             :   /// [idServer] The hostname of the identity server to communicate with. May optionally
     618             :   /// include a port. This parameter is ignored when the homeserver handles
     619             :   /// 3PID verification.
     620             :   ///
     621             :   /// This parameter is deprecated with a plan to be removed in a future specification
     622             :   /// version for `/account/password` and `/register` requests.
     623           0 :   Future<RequestTokenResponse> requestTokenTo3PIDEmail(
     624             :       String clientSecret, String email, int sendAttempt,
     625             :       {String? nextLink, String? idAccessToken, String? idServer}) async {
     626             :     final requestUri =
     627           0 :         Uri(path: '_matrix/client/v3/account/3pid/email/requestToken');
     628           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     629           0 :     request.headers['content-type'] = 'application/json';
     630           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     631           0 :       'client_secret': clientSecret,
     632           0 :       'email': email,
     633           0 :       if (nextLink != null) 'next_link': nextLink,
     634           0 :       'send_attempt': sendAttempt,
     635           0 :       if (idAccessToken != null) 'id_access_token': idAccessToken,
     636           0 :       if (idServer != null) 'id_server': idServer,
     637             :     }));
     638           0 :     final response = await httpClient.send(request);
     639           0 :     final responseBody = await response.stream.toBytes();
     640           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     641           0 :     final responseString = utf8.decode(responseBody);
     642           0 :     final json = jsonDecode(responseString);
     643           0 :     return RequestTokenResponse.fromJson(json as Map<String, Object?>);
     644             :   }
     645             : 
     646             :   /// The homeserver must check that the given phone number is **not**
     647             :   /// already associated with an account on this homeserver. This API should
     648             :   /// be used to request validation tokens when adding a phone number to an
     649             :   /// account. This API's parameters and response are identical to that of
     650             :   /// the [`/register/msisdn/requestToken`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv3registermsisdnrequesttoken)
     651             :   /// endpoint. The homeserver should validate
     652             :   /// the phone number itself, either by sending a validation message itself or by using
     653             :   /// a service it has control over.
     654             :   ///
     655             :   /// [clientSecret] A unique string generated by the client, and used to identify the
     656             :   /// validation attempt. It must be a string consisting of the characters
     657             :   /// `[0-9a-zA-Z.=_-]`. Its length must not exceed 255 characters and it
     658             :   /// must not be empty.
     659             :   ///
     660             :   ///
     661             :   /// [country] The two-letter uppercase ISO-3166-1 alpha-2 country code that the
     662             :   /// number in `phone_number` should be parsed as if it were dialled from.
     663             :   ///
     664             :   /// [nextLink] Optional. When the validation is completed, the identity server will
     665             :   /// redirect the user to this URL. This option is ignored when submitting
     666             :   /// 3PID validation information through a POST request.
     667             :   ///
     668             :   /// [phoneNumber] The phone number to validate.
     669             :   ///
     670             :   /// [sendAttempt] The server will only send an SMS if the `send_attempt` is a
     671             :   /// number greater than the most recent one which it has seen,
     672             :   /// scoped to that `country` + `phone_number` + `client_secret`
     673             :   /// triple. This is to avoid repeatedly sending the same SMS in
     674             :   /// the case of request retries between the POSTing user and the
     675             :   /// identity server. The client should increment this value if
     676             :   /// they desire a new SMS (e.g. a reminder) to be sent.
     677             :   ///
     678             :   /// [idAccessToken] An access token previously registered with the identity server. Servers
     679             :   /// can treat this as optional to distinguish between r0.5-compatible clients
     680             :   /// and this specification version.
     681             :   ///
     682             :   /// Required if an `id_server` is supplied.
     683             :   ///
     684             :   /// [idServer] The hostname of the identity server to communicate with. May optionally
     685             :   /// include a port. This parameter is ignored when the homeserver handles
     686             :   /// 3PID verification.
     687             :   ///
     688             :   /// This parameter is deprecated with a plan to be removed in a future specification
     689             :   /// version for `/account/password` and `/register` requests.
     690           0 :   Future<RequestTokenResponse> requestTokenTo3PIDMSISDN(
     691             :       String clientSecret, String country, String phoneNumber, int sendAttempt,
     692             :       {String? nextLink, String? idAccessToken, String? idServer}) async {
     693             :     final requestUri =
     694           0 :         Uri(path: '_matrix/client/v3/account/3pid/msisdn/requestToken');
     695           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     696           0 :     request.headers['content-type'] = 'application/json';
     697           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     698           0 :       'client_secret': clientSecret,
     699           0 :       'country': country,
     700           0 :       if (nextLink != null) 'next_link': nextLink,
     701           0 :       'phone_number': phoneNumber,
     702           0 :       'send_attempt': sendAttempt,
     703           0 :       if (idAccessToken != null) 'id_access_token': idAccessToken,
     704           0 :       if (idServer != null) 'id_server': idServer,
     705             :     }));
     706           0 :     final response = await httpClient.send(request);
     707           0 :     final responseBody = await response.stream.toBytes();
     708           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     709           0 :     final responseString = utf8.decode(responseBody);
     710           0 :     final json = jsonDecode(responseString);
     711           0 :     return RequestTokenResponse.fromJson(json as Map<String, Object?>);
     712             :   }
     713             : 
     714             :   /// Removes a user's third party identifier from the provided identity server
     715             :   /// without removing it from the homeserver.
     716             :   ///
     717             :   /// Unlike other endpoints, this endpoint does not take an `id_access_token`
     718             :   /// parameter because the homeserver is expected to sign the request to the
     719             :   /// identity server instead.
     720             :   ///
     721             :   /// [address] The third party address being removed.
     722             :   ///
     723             :   /// [idServer] The identity server to unbind from. If not provided, the homeserver
     724             :   /// MUST use the `id_server` the identifier was added through. If the
     725             :   /// homeserver does not know the original `id_server`, it MUST return
     726             :   /// a `id_server_unbind_result` of `no-support`.
     727             :   ///
     728             :   /// [medium] The medium of the third party identifier being removed.
     729             :   ///
     730             :   /// returns `id_server_unbind_result`:
     731             :   /// An indicator as to whether or not the identity server was able to unbind
     732             :   /// the 3PID. `success` indicates that the identity server has unbound the
     733             :   /// identifier whereas `no-support` indicates that the identity server
     734             :   /// refuses to support the request or the homeserver was not able to determine
     735             :   /// an identity server to unbind from.
     736           0 :   Future<IdServerUnbindResult> unbind3pidFromAccount(
     737             :       String address, ThirdPartyIdentifierMedium medium,
     738             :       {String? idServer}) async {
     739           0 :     final requestUri = Uri(path: '_matrix/client/v3/account/3pid/unbind');
     740           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     741           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     742           0 :     request.headers['content-type'] = 'application/json';
     743           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     744           0 :       'address': address,
     745           0 :       if (idServer != null) 'id_server': idServer,
     746           0 :       'medium': medium.name,
     747             :     }));
     748           0 :     final response = await httpClient.send(request);
     749           0 :     final responseBody = await response.stream.toBytes();
     750           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     751           0 :     final responseString = utf8.decode(responseBody);
     752           0 :     final json = jsonDecode(responseString);
     753             :     return IdServerUnbindResult.values
     754           0 :         .fromString(json['id_server_unbind_result'] as String)!;
     755             :   }
     756             : 
     757             :   /// Deactivate the user's account, removing all ability for the user to
     758             :   /// login again.
     759             :   ///
     760             :   /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api).
     761             :   ///
     762             :   /// An access token should be submitted to this endpoint if the client has
     763             :   /// an active session.
     764             :   ///
     765             :   /// The homeserver may change the flows available depending on whether a
     766             :   /// valid access token is provided.
     767             :   ///
     768             :   /// Unlike other endpoints, this endpoint does not take an `id_access_token`
     769             :   /// parameter because the homeserver is expected to sign the request to the
     770             :   /// identity server instead.
     771             :   ///
     772             :   /// [auth] Additional authentication information for the user-interactive authentication API.
     773             :   ///
     774             :   /// [idServer] The identity server to unbind all of the user's 3PIDs from.
     775             :   /// If not provided, the homeserver MUST use the `id_server`
     776             :   /// that was originally use to bind each identifier. If the
     777             :   /// homeserver does not know which `id_server` that was,
     778             :   /// it must return an `id_server_unbind_result` of
     779             :   /// `no-support`.
     780             :   ///
     781             :   /// returns `id_server_unbind_result`:
     782             :   /// An indicator as to whether or not the homeserver was able to unbind
     783             :   /// the user's 3PIDs from the identity server(s). `success` indicates
     784             :   /// that all identifiers have been unbound from the identity server while
     785             :   /// `no-support` indicates that one or more identifiers failed to unbind
     786             :   /// due to the identity server refusing the request or the homeserver
     787             :   /// being unable to determine an identity server to unbind from. This
     788             :   /// must be `success` if the homeserver has no identifiers to unbind
     789             :   /// for the user.
     790           0 :   Future<IdServerUnbindResult> deactivateAccount(
     791             :       {AuthenticationData? auth, String? idServer}) async {
     792           0 :     final requestUri = Uri(path: '_matrix/client/v3/account/deactivate');
     793           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     794           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     795           0 :     request.headers['content-type'] = 'application/json';
     796           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     797           0 :       if (auth != null) 'auth': auth.toJson(),
     798           0 :       if (idServer != null) 'id_server': idServer,
     799             :     }));
     800           0 :     final response = await httpClient.send(request);
     801           0 :     final responseBody = await response.stream.toBytes();
     802           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     803           0 :     final responseString = utf8.decode(responseBody);
     804           0 :     final json = jsonDecode(responseString);
     805             :     return IdServerUnbindResult.values
     806           0 :         .fromString(json['id_server_unbind_result'] as String)!;
     807             :   }
     808             : 
     809             :   /// Changes the password for an account on this homeserver.
     810             :   ///
     811             :   /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api) to
     812             :   /// ensure the user changing the password is actually the owner of the
     813             :   /// account.
     814             :   ///
     815             :   /// An access token should be submitted to this endpoint if the client has
     816             :   /// an active session.
     817             :   ///
     818             :   /// The homeserver may change the flows available depending on whether a
     819             :   /// valid access token is provided. The homeserver SHOULD NOT revoke the
     820             :   /// access token provided in the request. Whether other access tokens for
     821             :   /// the user are revoked depends on the request parameters.
     822             :   ///
     823             :   /// [auth] Additional authentication information for the user-interactive authentication API.
     824             :   ///
     825             :   /// [logoutDevices] Whether the user's other access tokens, and their associated devices, should be
     826             :   /// revoked if the request succeeds. Defaults to true.
     827             :   ///
     828             :   /// When `false`, the server can still take advantage of the [soft logout method](https://spec.matrix.org/unstable/client-server-api/#soft-logout)
     829             :   /// for the user's remaining devices.
     830             :   ///
     831             :   /// [newPassword] The new password for the account.
     832           1 :   Future<void> changePassword(String newPassword,
     833             :       {AuthenticationData? auth, bool? logoutDevices}) async {
     834           1 :     final requestUri = Uri(path: '_matrix/client/v3/account/password');
     835           3 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     836           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
     837           2 :     request.headers['content-type'] = 'application/json';
     838           4 :     request.bodyBytes = utf8.encode(jsonEncode({
     839           2 :       if (auth != null) 'auth': auth.toJson(),
     840           0 :       if (logoutDevices != null) 'logout_devices': logoutDevices,
     841           1 :       'new_password': newPassword,
     842             :     }));
     843           2 :     final response = await httpClient.send(request);
     844           2 :     final responseBody = await response.stream.toBytes();
     845           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     846           1 :     final responseString = utf8.decode(responseBody);
     847           1 :     final json = jsonDecode(responseString);
     848           1 :     return ignore(json);
     849             :   }
     850             : 
     851             :   /// The homeserver must check that the given email address **is
     852             :   /// associated** with an account on this homeserver. This API should be
     853             :   /// used to request validation tokens when authenticating for the
     854             :   /// `/account/password` endpoint.
     855             :   ///
     856             :   /// This API's parameters and response are identical to that of the
     857             :   /// [`/register/email/requestToken`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv3registeremailrequesttoken)
     858             :   /// endpoint, except that
     859             :   /// `M_THREEPID_NOT_FOUND` may be returned if no account matching the
     860             :   /// given email address could be found. The server may instead send an
     861             :   /// email to the given address prompting the user to create an account.
     862             :   /// `M_THREEPID_IN_USE` may not be returned.
     863             :   ///
     864             :   /// The homeserver should validate the email itself, either by sending a
     865             :   /// validation email itself or by using a service it has control over.
     866             :   ///
     867             :   /// [clientSecret] A unique string generated by the client, and used to identify the
     868             :   /// validation attempt. It must be a string consisting of the characters
     869             :   /// `[0-9a-zA-Z.=_-]`. Its length must not exceed 255 characters and it
     870             :   /// must not be empty.
     871             :   ///
     872             :   ///
     873             :   /// [email] The email address to validate.
     874             :   ///
     875             :   /// [nextLink] Optional. When the validation is completed, the identity server will
     876             :   /// redirect the user to this URL. This option is ignored when submitting
     877             :   /// 3PID validation information through a POST request.
     878             :   ///
     879             :   /// [sendAttempt] The server will only send an email if the `send_attempt`
     880             :   /// is a number greater than the most recent one which it has seen,
     881             :   /// scoped to that `email` + `client_secret` pair. This is to
     882             :   /// avoid repeatedly sending the same email in the case of request
     883             :   /// retries between the POSTing user and the identity server.
     884             :   /// The client should increment this value if they desire a new
     885             :   /// email (e.g. a reminder) to be sent. If they do not, the server
     886             :   /// should respond with success but not resend the email.
     887             :   ///
     888             :   /// [idAccessToken] An access token previously registered with the identity server. Servers
     889             :   /// can treat this as optional to distinguish between r0.5-compatible clients
     890             :   /// and this specification version.
     891             :   ///
     892             :   /// Required if an `id_server` is supplied.
     893             :   ///
     894             :   /// [idServer] The hostname of the identity server to communicate with. May optionally
     895             :   /// include a port. This parameter is ignored when the homeserver handles
     896             :   /// 3PID verification.
     897             :   ///
     898             :   /// This parameter is deprecated with a plan to be removed in a future specification
     899             :   /// version for `/account/password` and `/register` requests.
     900           0 :   Future<RequestTokenResponse> requestTokenToResetPasswordEmail(
     901             :       String clientSecret, String email, int sendAttempt,
     902             :       {String? nextLink, String? idAccessToken, String? idServer}) async {
     903             :     final requestUri =
     904           0 :         Uri(path: '_matrix/client/v3/account/password/email/requestToken');
     905           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     906           0 :     request.headers['content-type'] = 'application/json';
     907           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     908           0 :       'client_secret': clientSecret,
     909           0 :       'email': email,
     910           0 :       if (nextLink != null) 'next_link': nextLink,
     911           0 :       'send_attempt': sendAttempt,
     912           0 :       if (idAccessToken != null) 'id_access_token': idAccessToken,
     913           0 :       if (idServer != null) 'id_server': idServer,
     914             :     }));
     915           0 :     final response = await httpClient.send(request);
     916           0 :     final responseBody = await response.stream.toBytes();
     917           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     918           0 :     final responseString = utf8.decode(responseBody);
     919           0 :     final json = jsonDecode(responseString);
     920           0 :     return RequestTokenResponse.fromJson(json as Map<String, Object?>);
     921             :   }
     922             : 
     923             :   /// The homeserver must check that the given phone number **is
     924             :   /// associated** with an account on this homeserver. This API should be
     925             :   /// used to request validation tokens when authenticating for the
     926             :   /// `/account/password` endpoint.
     927             :   ///
     928             :   /// This API's parameters and response are identical to that of the
     929             :   /// [`/register/msisdn/requestToken`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv3registermsisdnrequesttoken)
     930             :   /// endpoint, except that
     931             :   /// `M_THREEPID_NOT_FOUND` may be returned if no account matching the
     932             :   /// given phone number could be found. The server may instead send the SMS
     933             :   /// to the given phone number prompting the user to create an account.
     934             :   /// `M_THREEPID_IN_USE` may not be returned.
     935             :   ///
     936             :   /// The homeserver should validate the phone number itself, either by sending a
     937             :   /// validation message itself or by using a service it has control over.
     938             :   ///
     939             :   /// [clientSecret] A unique string generated by the client, and used to identify the
     940             :   /// validation attempt. It must be a string consisting of the characters
     941             :   /// `[0-9a-zA-Z.=_-]`. Its length must not exceed 255 characters and it
     942             :   /// must not be empty.
     943             :   ///
     944             :   ///
     945             :   /// [country] The two-letter uppercase ISO-3166-1 alpha-2 country code that the
     946             :   /// number in `phone_number` should be parsed as if it were dialled from.
     947             :   ///
     948             :   /// [nextLink] Optional. When the validation is completed, the identity server will
     949             :   /// redirect the user to this URL. This option is ignored when submitting
     950             :   /// 3PID validation information through a POST request.
     951             :   ///
     952             :   /// [phoneNumber] The phone number to validate.
     953             :   ///
     954             :   /// [sendAttempt] The server will only send an SMS if the `send_attempt` is a
     955             :   /// number greater than the most recent one which it has seen,
     956             :   /// scoped to that `country` + `phone_number` + `client_secret`
     957             :   /// triple. This is to avoid repeatedly sending the same SMS in
     958             :   /// the case of request retries between the POSTing user and the
     959             :   /// identity server. The client should increment this value if
     960             :   /// they desire a new SMS (e.g. a reminder) to be sent.
     961             :   ///
     962             :   /// [idAccessToken] An access token previously registered with the identity server. Servers
     963             :   /// can treat this as optional to distinguish between r0.5-compatible clients
     964             :   /// and this specification version.
     965             :   ///
     966             :   /// Required if an `id_server` is supplied.
     967             :   ///
     968             :   /// [idServer] The hostname of the identity server to communicate with. May optionally
     969             :   /// include a port. This parameter is ignored when the homeserver handles
     970             :   /// 3PID verification.
     971             :   ///
     972             :   /// This parameter is deprecated with a plan to be removed in a future specification
     973             :   /// version for `/account/password` and `/register` requests.
     974           0 :   Future<RequestTokenResponse> requestTokenToResetPasswordMSISDN(
     975             :       String clientSecret, String country, String phoneNumber, int sendAttempt,
     976             :       {String? nextLink, String? idAccessToken, String? idServer}) async {
     977             :     final requestUri =
     978           0 :         Uri(path: '_matrix/client/v3/account/password/msisdn/requestToken');
     979           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
     980           0 :     request.headers['content-type'] = 'application/json';
     981           0 :     request.bodyBytes = utf8.encode(jsonEncode({
     982           0 :       'client_secret': clientSecret,
     983           0 :       'country': country,
     984           0 :       if (nextLink != null) 'next_link': nextLink,
     985           0 :       'phone_number': phoneNumber,
     986           0 :       'send_attempt': sendAttempt,
     987           0 :       if (idAccessToken != null) 'id_access_token': idAccessToken,
     988           0 :       if (idServer != null) 'id_server': idServer,
     989             :     }));
     990           0 :     final response = await httpClient.send(request);
     991           0 :     final responseBody = await response.stream.toBytes();
     992           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
     993           0 :     final responseString = utf8.decode(responseBody);
     994           0 :     final json = jsonDecode(responseString);
     995           0 :     return RequestTokenResponse.fromJson(json as Map<String, Object?>);
     996             :   }
     997             : 
     998             :   /// Gets information about the owner of a given access token.
     999             :   ///
    1000             :   /// Note that, as with the rest of the Client-Server API,
    1001             :   /// Application Services may masquerade as users within their
    1002             :   /// namespace by giving a `user_id` query parameter. In this
    1003             :   /// situation, the server should verify that the given `user_id`
    1004             :   /// is registered by the appservice, and return it in the response
    1005             :   /// body.
    1006           0 :   Future<TokenOwnerInfo> getTokenOwner() async {
    1007           0 :     final requestUri = Uri(path: '_matrix/client/v3/account/whoami');
    1008           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1009           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1010           0 :     final response = await httpClient.send(request);
    1011           0 :     final responseBody = await response.stream.toBytes();
    1012           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1013           0 :     final responseString = utf8.decode(responseBody);
    1014           0 :     final json = jsonDecode(responseString);
    1015           0 :     return TokenOwnerInfo.fromJson(json as Map<String, Object?>);
    1016             :   }
    1017             : 
    1018             :   /// Gets information about a particular user.
    1019             :   ///
    1020             :   /// This API may be restricted to only be called by the user being looked
    1021             :   /// up, or by a server admin. Server-local administrator privileges are not
    1022             :   /// specified in this document.
    1023             :   ///
    1024             :   /// [userId] The user to look up.
    1025           0 :   Future<WhoIsInfo> getWhoIs(String userId) async {
    1026           0 :     final requestUri = Uri(
    1027           0 :         path: '_matrix/client/v3/admin/whois/${Uri.encodeComponent(userId)}');
    1028           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1029           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1030           0 :     final response = await httpClient.send(request);
    1031           0 :     final responseBody = await response.stream.toBytes();
    1032           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1033           0 :     final responseString = utf8.decode(responseBody);
    1034           0 :     final json = jsonDecode(responseString);
    1035           0 :     return WhoIsInfo.fromJson(json as Map<String, Object?>);
    1036             :   }
    1037             : 
    1038             :   /// Gets information about the server's supported feature set
    1039             :   /// and other relevant capabilities.
    1040             :   ///
    1041             :   /// returns `capabilities`:
    1042             :   /// The custom capabilities the server supports, using the
    1043             :   /// Java package naming convention.
    1044           0 :   Future<Capabilities> getCapabilities() async {
    1045           0 :     final requestUri = Uri(path: '_matrix/client/v3/capabilities');
    1046           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1047           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1048           0 :     final response = await httpClient.send(request);
    1049           0 :     final responseBody = await response.stream.toBytes();
    1050           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1051           0 :     final responseString = utf8.decode(responseBody);
    1052           0 :     final json = jsonDecode(responseString);
    1053           0 :     return Capabilities.fromJson(json['capabilities'] as Map<String, Object?>);
    1054             :   }
    1055             : 
    1056             :   /// Create a new room with various configuration options.
    1057             :   ///
    1058             :   /// The server MUST apply the normal state resolution rules when creating
    1059             :   /// the new room, including checking power levels for each event. It MUST
    1060             :   /// apply the events implied by the request in the following order:
    1061             :   ///
    1062             :   /// 1. The `m.room.create` event itself. Must be the first event in the
    1063             :   ///    room.
    1064             :   ///
    1065             :   /// 2. An `m.room.member` event for the creator to join the room. This is
    1066             :   ///    needed so the remaining events can be sent.
    1067             :   ///
    1068             :   /// 3. A default `m.room.power_levels` event, giving the room creator
    1069             :   ///    (and not other members) permission to send state events. Overridden
    1070             :   ///    by the `power_level_content_override` parameter.
    1071             :   ///
    1072             :   /// 4. An `m.room.canonical_alias` event if `room_alias_name` is given.
    1073             :   ///
    1074             :   /// 5. Events set by the `preset`. Currently these are the `m.room.join_rules`,
    1075             :   ///    `m.room.history_visibility`, and `m.room.guest_access` state events.
    1076             :   ///
    1077             :   /// 6. Events listed in `initial_state`, in the order that they are
    1078             :   ///    listed.
    1079             :   ///
    1080             :   /// 7. Events implied by `name` and `topic` (`m.room.name` and `m.room.topic`
    1081             :   ///    state events).
    1082             :   ///
    1083             :   /// 8. Invite events implied by `invite` and `invite_3pid` (`m.room.member` with
    1084             :   ///    `membership: invite` and `m.room.third_party_invite`).
    1085             :   ///
    1086             :   /// The available presets do the following with respect to room state:
    1087             :   ///
    1088             :   /// | Preset                 | `join_rules` | `history_visibility` | `guest_access` | Other |
    1089             :   /// |------------------------|--------------|----------------------|----------------|-------|
    1090             :   /// | `private_chat`         | `invite`     | `shared`             | `can_join`     |       |
    1091             :   /// | `trusted_private_chat` | `invite`     | `shared`             | `can_join`     | All invitees are given the same power level as the room creator. |
    1092             :   /// | `public_chat`          | `public`     | `shared`             | `forbidden`    |       |
    1093             :   ///
    1094             :   /// The server will create a `m.room.create` event in the room with the
    1095             :   /// requesting user as the creator, alongside other keys provided in the
    1096             :   /// `creation_content`.
    1097             :   ///
    1098             :   /// [creationContent] Extra keys, such as `m.federate`, to be added to the content
    1099             :   /// of the [`m.room.create`](https://spec.matrix.org/unstable/client-server-api/#mroomcreate) event. The server will overwrite the following
    1100             :   /// keys: `creator`, `room_version`. Future versions of the specification
    1101             :   /// may allow the server to overwrite other keys.
    1102             :   ///
    1103             :   /// [initialState] A list of state events to set in the new room. This allows
    1104             :   /// the user to override the default state events set in the new
    1105             :   /// room. The expected format of the state events are an object
    1106             :   /// with type, state_key and content keys set.
    1107             :   ///
    1108             :   /// Takes precedence over events set by `preset`, but gets
    1109             :   /// overridden by `name` and `topic` keys.
    1110             :   ///
    1111             :   /// [invite] A list of user IDs to invite to the room. This will tell the
    1112             :   /// server to invite everyone in the list to the newly created room.
    1113             :   ///
    1114             :   /// [invite3pid] A list of objects representing third party IDs to invite into
    1115             :   /// the room.
    1116             :   ///
    1117             :   /// [isDirect] This flag makes the server set the `is_direct` flag on the
    1118             :   /// `m.room.member` events sent to the users in `invite` and
    1119             :   /// `invite_3pid`. See [Direct Messaging](https://spec.matrix.org/unstable/client-server-api/#direct-messaging) for more information.
    1120             :   ///
    1121             :   /// [name] If this is included, an `m.room.name` event will be sent
    1122             :   /// into the room to indicate the name of the room. See Room
    1123             :   /// Events for more information on `m.room.name`.
    1124             :   ///
    1125             :   /// [powerLevelContentOverride] The power level content to override in the default power level
    1126             :   /// event. This object is applied on top of the generated
    1127             :   /// [`m.room.power_levels`](https://spec.matrix.org/unstable/client-server-api/#mroompower_levels)
    1128             :   /// event content prior to it being sent to the room. Defaults to
    1129             :   /// overriding nothing.
    1130             :   ///
    1131             :   /// [preset] Convenience parameter for setting various default state events
    1132             :   /// based on a preset.
    1133             :   ///
    1134             :   /// If unspecified, the server should use the `visibility` to determine
    1135             :   /// which preset to use. A visbility of `public` equates to a preset of
    1136             :   /// `public_chat` and `private` visibility equates to a preset of
    1137             :   /// `private_chat`.
    1138             :   ///
    1139             :   /// [roomAliasName] The desired room alias **local part**. If this is included, a
    1140             :   /// room alias will be created and mapped to the newly created
    1141             :   /// room. The alias will belong on the *same* homeserver which
    1142             :   /// created the room. For example, if this was set to "foo" and
    1143             :   /// sent to the homeserver "example.com" the complete room alias
    1144             :   /// would be `#foo:example.com`.
    1145             :   ///
    1146             :   /// The complete room alias will become the canonical alias for
    1147             :   /// the room and an `m.room.canonical_alias` event will be sent
    1148             :   /// into the room.
    1149             :   ///
    1150             :   /// [roomVersion] The room version to set for the room. If not provided, the homeserver is
    1151             :   /// to use its configured default. If provided, the homeserver will return a
    1152             :   /// 400 error with the errcode `M_UNSUPPORTED_ROOM_VERSION` if it does not
    1153             :   /// support the room version.
    1154             :   ///
    1155             :   /// [topic] If this is included, an `m.room.topic` event will be sent
    1156             :   /// into the room to indicate the topic for the room. See Room
    1157             :   /// Events for more information on `m.room.topic`.
    1158             :   ///
    1159             :   /// [visibility] A `public` visibility indicates that the room will be shown
    1160             :   /// in the published room list. A `private` visibility will hide
    1161             :   /// the room from the published room list. Rooms default to
    1162             :   /// `private` visibility if this key is not included. NB: This
    1163             :   /// should not be confused with `join_rules` which also uses the
    1164             :   /// word `public`.
    1165             :   ///
    1166             :   /// returns `room_id`:
    1167             :   /// The created room's ID.
    1168           6 :   Future<String> createRoom(
    1169             :       {Map<String, Object?>? creationContent,
    1170             :       List<StateEvent>? initialState,
    1171             :       List<String>? invite,
    1172             :       List<Invite3pid>? invite3pid,
    1173             :       bool? isDirect,
    1174             :       String? name,
    1175             :       Map<String, Object?>? powerLevelContentOverride,
    1176             :       CreateRoomPreset? preset,
    1177             :       String? roomAliasName,
    1178             :       String? roomVersion,
    1179             :       String? topic,
    1180             :       Visibility? visibility}) async {
    1181           6 :     final requestUri = Uri(path: '_matrix/client/v3/createRoom');
    1182          18 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1183          24 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1184          12 :     request.headers['content-type'] = 'application/json';
    1185          24 :     request.bodyBytes = utf8.encode(jsonEncode({
    1186           1 :       if (creationContent != null) 'creation_content': creationContent,
    1187             :       if (initialState != null)
    1188          10 :         'initial_state': initialState.map((v) => v.toJson()).toList(),
    1189          24 :       if (invite != null) 'invite': invite.map((v) => v).toList(),
    1190             :       if (invite3pid != null)
    1191           0 :         'invite_3pid': invite3pid.map((v) => v.toJson()).toList(),
    1192           6 :       if (isDirect != null) 'is_direct': isDirect,
    1193           1 :       if (name != null) 'name': name,
    1194             :       if (powerLevelContentOverride != null)
    1195           1 :         'power_level_content_override': powerLevelContentOverride,
    1196          12 :       if (preset != null) 'preset': preset.name,
    1197           1 :       if (roomAliasName != null) 'room_alias_name': roomAliasName,
    1198           1 :       if (roomVersion != null) 'room_version': roomVersion,
    1199           1 :       if (topic != null) 'topic': topic,
    1200           2 :       if (visibility != null) 'visibility': visibility.name,
    1201             :     }));
    1202          12 :     final response = await httpClient.send(request);
    1203          12 :     final responseBody = await response.stream.toBytes();
    1204          12 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1205           6 :     final responseString = utf8.decode(responseBody);
    1206           6 :     final json = jsonDecode(responseString);
    1207           6 :     return json['room_id'] as String;
    1208             :   }
    1209             : 
    1210             :   /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api).
    1211             :   ///
    1212             :   /// Deletes the given devices, and invalidates any access token associated with them.
    1213             :   ///
    1214             :   /// [auth] Additional authentication information for the
    1215             :   /// user-interactive authentication API.
    1216             :   ///
    1217             :   /// [devices] The list of device IDs to delete.
    1218           0 :   Future<void> deleteDevices(List<String> devices,
    1219             :       {AuthenticationData? auth}) async {
    1220           0 :     final requestUri = Uri(path: '_matrix/client/v3/delete_devices');
    1221           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1222           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1223           0 :     request.headers['content-type'] = 'application/json';
    1224           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    1225           0 :       if (auth != null) 'auth': auth.toJson(),
    1226           0 :       'devices': devices.map((v) => v).toList(),
    1227             :     }));
    1228           0 :     final response = await httpClient.send(request);
    1229           0 :     final responseBody = await response.stream.toBytes();
    1230           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1231           0 :     final responseString = utf8.decode(responseBody);
    1232           0 :     final json = jsonDecode(responseString);
    1233           0 :     return ignore(json);
    1234             :   }
    1235             : 
    1236             :   /// Gets information about all devices for the current user.
    1237             :   ///
    1238             :   /// returns `devices`:
    1239             :   /// A list of all registered devices for this user.
    1240           0 :   Future<List<Device>?> getDevices() async {
    1241           0 :     final requestUri = Uri(path: '_matrix/client/v3/devices');
    1242           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1243           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1244           0 :     final response = await httpClient.send(request);
    1245           0 :     final responseBody = await response.stream.toBytes();
    1246           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1247           0 :     final responseString = utf8.decode(responseBody);
    1248           0 :     final json = jsonDecode(responseString);
    1249           0 :     return ((v) => v != null
    1250             :         ? (v as List)
    1251           0 :             .map((v) => Device.fromJson(v as Map<String, Object?>))
    1252           0 :             .toList()
    1253           0 :         : null)(json['devices']);
    1254             :   }
    1255             : 
    1256             :   /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api).
    1257             :   ///
    1258             :   /// Deletes the given device, and invalidates any access token associated with it.
    1259             :   ///
    1260             :   /// [deviceId] The device to delete.
    1261             :   ///
    1262             :   /// [auth] Additional authentication information for the
    1263             :   /// user-interactive authentication API.
    1264           0 :   Future<void> deleteDevice(String deviceId, {AuthenticationData? auth}) async {
    1265             :     final requestUri =
    1266           0 :         Uri(path: '_matrix/client/v3/devices/${Uri.encodeComponent(deviceId)}');
    1267           0 :     final request = Request('DELETE', baseUri!.resolveUri(requestUri));
    1268           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1269           0 :     request.headers['content-type'] = 'application/json';
    1270           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    1271           0 :       if (auth != null) 'auth': auth.toJson(),
    1272             :     }));
    1273           0 :     final response = await httpClient.send(request);
    1274           0 :     final responseBody = await response.stream.toBytes();
    1275           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1276           0 :     final responseString = utf8.decode(responseBody);
    1277           0 :     final json = jsonDecode(responseString);
    1278           0 :     return ignore(json);
    1279             :   }
    1280             : 
    1281             :   /// Gets information on a single device, by device id.
    1282             :   ///
    1283             :   /// [deviceId] The device to retrieve.
    1284           0 :   Future<Device> getDevice(String deviceId) async {
    1285             :     final requestUri =
    1286           0 :         Uri(path: '_matrix/client/v3/devices/${Uri.encodeComponent(deviceId)}');
    1287           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1288           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1289           0 :     final response = await httpClient.send(request);
    1290           0 :     final responseBody = await response.stream.toBytes();
    1291           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1292           0 :     final responseString = utf8.decode(responseBody);
    1293           0 :     final json = jsonDecode(responseString);
    1294           0 :     return Device.fromJson(json as Map<String, Object?>);
    1295             :   }
    1296             : 
    1297             :   /// Updates the metadata on the given device.
    1298             :   ///
    1299             :   /// [deviceId] The device to update.
    1300             :   ///
    1301             :   /// [displayName] The new display name for this device. If not given, the
    1302             :   /// display name is unchanged.
    1303           0 :   Future<void> updateDevice(String deviceId, {String? displayName}) async {
    1304             :     final requestUri =
    1305           0 :         Uri(path: '_matrix/client/v3/devices/${Uri.encodeComponent(deviceId)}');
    1306           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    1307           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1308           0 :     request.headers['content-type'] = 'application/json';
    1309           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    1310           0 :       if (displayName != null) 'display_name': displayName,
    1311             :     }));
    1312           0 :     final response = await httpClient.send(request);
    1313           0 :     final responseBody = await response.stream.toBytes();
    1314           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1315           0 :     final responseString = utf8.decode(responseBody);
    1316           0 :     final json = jsonDecode(responseString);
    1317           0 :     return ignore(json);
    1318             :   }
    1319             : 
    1320             :   /// Updates the visibility of a given room on the application service's room
    1321             :   /// directory.
    1322             :   ///
    1323             :   /// This API is similar to the room directory visibility API used by clients
    1324             :   /// to update the homeserver's more general room directory.
    1325             :   ///
    1326             :   /// This API requires the use of an application service access token (`as_token`)
    1327             :   /// instead of a typical client's access_token. This API cannot be invoked by
    1328             :   /// users who are not identified as application services.
    1329             :   ///
    1330             :   /// [networkId] The protocol (network) ID to update the room list for. This would
    1331             :   /// have been provided by the application service as being listed as
    1332             :   /// a supported protocol.
    1333             :   ///
    1334             :   /// [roomId] The room ID to add to the directory.
    1335             :   ///
    1336             :   /// [visibility] Whether the room should be visible (public) in the directory
    1337             :   /// or not (private).
    1338           0 :   Future<Map<String, Object?>> updateAppserviceRoomDirectoryVisibility(
    1339             :       String networkId, String roomId, Visibility visibility) async {
    1340           0 :     final requestUri = Uri(
    1341             :         path:
    1342           0 :             '_matrix/client/v3/directory/list/appservice/${Uri.encodeComponent(networkId)}/${Uri.encodeComponent(roomId)}');
    1343           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    1344           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1345           0 :     request.headers['content-type'] = 'application/json';
    1346           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    1347           0 :       'visibility': visibility.name,
    1348             :     }));
    1349           0 :     final response = await httpClient.send(request);
    1350           0 :     final responseBody = await response.stream.toBytes();
    1351           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1352           0 :     final responseString = utf8.decode(responseBody);
    1353           0 :     final json = jsonDecode(responseString);
    1354             :     return json as Map<String, Object?>;
    1355             :   }
    1356             : 
    1357             :   /// Gets the visibility of a given room on the server's public room directory.
    1358             :   ///
    1359             :   /// [roomId] The room ID.
    1360             :   ///
    1361             :   /// returns `visibility`:
    1362             :   /// The visibility of the room in the directory.
    1363           0 :   Future<Visibility?> getRoomVisibilityOnDirectory(String roomId) async {
    1364           0 :     final requestUri = Uri(
    1365             :         path:
    1366           0 :             '_matrix/client/v3/directory/list/room/${Uri.encodeComponent(roomId)}');
    1367           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1368           0 :     final response = await httpClient.send(request);
    1369           0 :     final responseBody = await response.stream.toBytes();
    1370           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1371           0 :     final responseString = utf8.decode(responseBody);
    1372           0 :     final json = jsonDecode(responseString);
    1373           0 :     return ((v) => v != null
    1374           0 :         ? Visibility.values.fromString(v as String)!
    1375           0 :         : null)(json['visibility']);
    1376             :   }
    1377             : 
    1378             :   /// Sets the visibility of a given room in the server's public room
    1379             :   /// directory.
    1380             :   ///
    1381             :   /// Servers may choose to implement additional access control checks
    1382             :   /// here, for instance that room visibility can only be changed by
    1383             :   /// the room creator or a server administrator.
    1384             :   ///
    1385             :   /// [roomId] The room ID.
    1386             :   ///
    1387             :   /// [visibility] The new visibility setting for the room.
    1388             :   /// Defaults to 'public'.
    1389           0 :   Future<void> setRoomVisibilityOnDirectory(String roomId,
    1390             :       {Visibility? visibility}) async {
    1391           0 :     final requestUri = Uri(
    1392             :         path:
    1393           0 :             '_matrix/client/v3/directory/list/room/${Uri.encodeComponent(roomId)}');
    1394           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    1395           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1396           0 :     request.headers['content-type'] = 'application/json';
    1397           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    1398           0 :       if (visibility != null) 'visibility': visibility.name,
    1399             :     }));
    1400           0 :     final response = await httpClient.send(request);
    1401           0 :     final responseBody = await response.stream.toBytes();
    1402           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1403           0 :     final responseString = utf8.decode(responseBody);
    1404           0 :     final json = jsonDecode(responseString);
    1405           0 :     return ignore(json);
    1406             :   }
    1407             : 
    1408             :   /// Remove a mapping of room alias to room ID.
    1409             :   ///
    1410             :   /// Servers may choose to implement additional access control checks here, for instance that
    1411             :   /// room aliases can only be deleted by their creator or a server administrator.
    1412             :   ///
    1413             :   /// **Note:**
    1414             :   /// Servers may choose to update the `alt_aliases` for the `m.room.canonical_alias`
    1415             :   /// state event in the room when an alias is removed. Servers which choose to update the
    1416             :   /// canonical alias event are recommended to, in addition to their other relevant permission
    1417             :   /// checks, delete the alias and return a successful response even if the user does not
    1418             :   /// have permission to update the `m.room.canonical_alias` event.
    1419             :   ///
    1420             :   /// [roomAlias] The room alias to remove. Its format is defined
    1421             :   /// [in the appendices](https://spec.matrix.org/unstable/appendices/#room-aliases).
    1422             :   ///
    1423           0 :   Future<void> deleteRoomAlias(String roomAlias) async {
    1424           0 :     final requestUri = Uri(
    1425             :         path:
    1426           0 :             '_matrix/client/v3/directory/room/${Uri.encodeComponent(roomAlias)}');
    1427           0 :     final request = Request('DELETE', baseUri!.resolveUri(requestUri));
    1428           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1429           0 :     final response = await httpClient.send(request);
    1430           0 :     final responseBody = await response.stream.toBytes();
    1431           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1432           0 :     final responseString = utf8.decode(responseBody);
    1433           0 :     final json = jsonDecode(responseString);
    1434           0 :     return ignore(json);
    1435             :   }
    1436             : 
    1437             :   /// Requests that the server resolve a room alias to a room ID.
    1438             :   ///
    1439             :   /// The server will use the federation API to resolve the alias if the
    1440             :   /// domain part of the alias does not correspond to the server's own
    1441             :   /// domain.
    1442             :   ///
    1443             :   /// [roomAlias] The room alias. Its format is defined
    1444             :   /// [in the appendices](https://spec.matrix.org/unstable/appendices/#room-aliases).
    1445             :   ///
    1446           0 :   Future<GetRoomIdByAliasResponse> getRoomIdByAlias(String roomAlias) async {
    1447           0 :     final requestUri = Uri(
    1448             :         path:
    1449           0 :             '_matrix/client/v3/directory/room/${Uri.encodeComponent(roomAlias)}');
    1450           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1451           0 :     final response = await httpClient.send(request);
    1452           0 :     final responseBody = await response.stream.toBytes();
    1453           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1454           0 :     final responseString = utf8.decode(responseBody);
    1455           0 :     final json = jsonDecode(responseString);
    1456           0 :     return GetRoomIdByAliasResponse.fromJson(json as Map<String, Object?>);
    1457             :   }
    1458             : 
    1459             :   ///
    1460             :   ///
    1461             :   /// [roomAlias] The room alias to set. Its format is defined
    1462             :   /// [in the appendices](https://spec.matrix.org/unstable/appendices/#room-aliases).
    1463             :   ///
    1464             :   ///
    1465             :   /// [roomId] The room ID to set.
    1466           0 :   Future<void> setRoomAlias(String roomAlias, String roomId) async {
    1467           0 :     final requestUri = Uri(
    1468             :         path:
    1469           0 :             '_matrix/client/v3/directory/room/${Uri.encodeComponent(roomAlias)}');
    1470           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    1471           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1472           0 :     request.headers['content-type'] = 'application/json';
    1473           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    1474             :       'room_id': roomId,
    1475             :     }));
    1476           0 :     final response = await httpClient.send(request);
    1477           0 :     final responseBody = await response.stream.toBytes();
    1478           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1479           0 :     final responseString = utf8.decode(responseBody);
    1480           0 :     final json = jsonDecode(responseString);
    1481           0 :     return ignore(json);
    1482             :   }
    1483             : 
    1484             :   /// This will listen for new events and return them to the caller. This will
    1485             :   /// block until an event is received, or until the `timeout` is reached.
    1486             :   ///
    1487             :   /// This endpoint was deprecated in r0 of this specification. Clients
    1488             :   /// should instead call the [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync)
    1489             :   /// endpoint with a `since` parameter. See
    1490             :   /// the [migration guide](https://matrix.org/docs/guides/migrating-from-client-server-api-v-1#deprecated-endpoints).
    1491             :   ///
    1492             :   /// [from] The token to stream from. This token is either from a previous
    1493             :   /// request to this API or from the initial sync API.
    1494             :   ///
    1495             :   /// [timeout] The maximum time in milliseconds to wait for an event.
    1496           0 :   @Deprecated('message')
    1497             :   Future<GetEventsResponse> getEvents({String? from, int? timeout}) async {
    1498           0 :     final requestUri = Uri(path: '_matrix/client/v3/events', queryParameters: {
    1499           0 :       if (from != null) 'from': from,
    1500           0 :       if (timeout != null) 'timeout': timeout.toString(),
    1501             :     });
    1502           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1503           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1504           0 :     final response = await httpClient.send(request);
    1505           0 :     final responseBody = await response.stream.toBytes();
    1506           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1507           0 :     final responseString = utf8.decode(responseBody);
    1508           0 :     final json = jsonDecode(responseString);
    1509           0 :     return GetEventsResponse.fromJson(json as Map<String, Object?>);
    1510             :   }
    1511             : 
    1512             :   /// This will listen for new events related to a particular room and return
    1513             :   /// them to the caller. This will block until an event is received, or until
    1514             :   /// the `timeout` is reached.
    1515             :   ///
    1516             :   /// This API is the same as the normal `/events` endpoint, but can be
    1517             :   /// called by users who have not joined the room.
    1518             :   ///
    1519             :   /// Note that the normal `/events` endpoint has been deprecated. This
    1520             :   /// API will also be deprecated at some point, but its replacement is not
    1521             :   /// yet known.
    1522             :   ///
    1523             :   /// [from] The token to stream from. This token is either from a previous
    1524             :   /// request to this API or from the initial sync API.
    1525             :   ///
    1526             :   /// [timeout] The maximum time in milliseconds to wait for an event.
    1527             :   ///
    1528             :   /// [roomId] The room ID for which events should be returned.
    1529           0 :   Future<PeekEventsResponse> peekEvents(
    1530             :       {String? from, int? timeout, String? roomId}) async {
    1531           0 :     final requestUri = Uri(path: '_matrix/client/v3/events', queryParameters: {
    1532           0 :       if (from != null) 'from': from,
    1533           0 :       if (timeout != null) 'timeout': timeout.toString(),
    1534           0 :       if (roomId != null) 'room_id': roomId,
    1535             :     });
    1536           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1537           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1538           0 :     final response = await httpClient.send(request);
    1539           0 :     final responseBody = await response.stream.toBytes();
    1540           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1541           0 :     final responseString = utf8.decode(responseBody);
    1542           0 :     final json = jsonDecode(responseString);
    1543           0 :     return PeekEventsResponse.fromJson(json as Map<String, Object?>);
    1544             :   }
    1545             : 
    1546             :   /// Get a single event based on `event_id`. You must have permission to
    1547             :   /// retrieve this event e.g. by being a member in the room for this event.
    1548             :   ///
    1549             :   /// This endpoint was deprecated in r0 of this specification. Clients
    1550             :   /// should instead call the
    1551             :   /// [/rooms/{roomId}/event/{eventId}](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3roomsroomideventeventid) API
    1552             :   /// or the [/rooms/{roomId}/context/{eventId](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3roomsroomidcontexteventid) API.
    1553             :   ///
    1554             :   /// [eventId] The event ID to get.
    1555           0 :   @Deprecated('message')
    1556             :   Future<MatrixEvent> getOneEvent(String eventId) async {
    1557             :     final requestUri =
    1558           0 :         Uri(path: '_matrix/client/v3/events/${Uri.encodeComponent(eventId)}');
    1559           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1560           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1561           0 :     final response = await httpClient.send(request);
    1562           0 :     final responseBody = await response.stream.toBytes();
    1563           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1564           0 :     final responseString = utf8.decode(responseBody);
    1565           0 :     final json = jsonDecode(responseString);
    1566           0 :     return MatrixEvent.fromJson(json as Map<String, Object?>);
    1567             :   }
    1568             : 
    1569             :   /// *Note that this API takes either a room ID or alias, unlike* `/rooms/{roomId}/join`.
    1570             :   ///
    1571             :   /// This API starts a user participating in a particular room, if that user
    1572             :   /// is allowed to participate in that room. After this call, the client is
    1573             :   /// allowed to see all current state events in the room, and all subsequent
    1574             :   /// events associated with the room until the user leaves the room.
    1575             :   ///
    1576             :   /// After a user has joined a room, the room will appear as an entry in the
    1577             :   /// response of the [`/initialSync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3initialsync)
    1578             :   /// and [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync) APIs.
    1579             :   ///
    1580             :   /// [roomIdOrAlias] The room identifier or alias to join.
    1581             :   ///
    1582             :   /// [serverName] The servers to attempt to join the room through. One of the servers
    1583             :   /// must be participating in the room.
    1584             :   ///
    1585             :   /// [reason] Optional reason to be included as the `reason` on the subsequent
    1586             :   /// membership event.
    1587             :   ///
    1588             :   /// [thirdPartySigned] If a `third_party_signed` was supplied, the homeserver must verify
    1589             :   /// that it matches a pending `m.room.third_party_invite` event in the
    1590             :   /// room, and perform key validity checking if required by the event.
    1591             :   ///
    1592             :   /// returns `room_id`:
    1593             :   /// The joined room ID.
    1594           1 :   Future<String> joinRoom(String roomIdOrAlias,
    1595             :       {List<String>? serverName,
    1596             :       String? reason,
    1597             :       ThirdPartySigned? thirdPartySigned}) async {
    1598           1 :     final requestUri = Uri(
    1599           2 :         path: '_matrix/client/v3/join/${Uri.encodeComponent(roomIdOrAlias)}',
    1600           1 :         queryParameters: {
    1601             :           if (serverName != null)
    1602           0 :             'server_name': serverName.map((v) => v).toList(),
    1603             :         });
    1604           3 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1605           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1606           2 :     request.headers['content-type'] = 'application/json';
    1607           4 :     request.bodyBytes = utf8.encode(jsonEncode({
    1608           0 :       if (reason != null) 'reason': reason,
    1609             :       if (thirdPartySigned != null)
    1610           0 :         'third_party_signed': thirdPartySigned.toJson(),
    1611             :     }));
    1612           2 :     final response = await httpClient.send(request);
    1613           2 :     final responseBody = await response.stream.toBytes();
    1614           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1615           1 :     final responseString = utf8.decode(responseBody);
    1616           1 :     final json = jsonDecode(responseString);
    1617           1 :     return json['room_id'] as String;
    1618             :   }
    1619             : 
    1620             :   /// This API returns a list of the user's current rooms.
    1621             :   ///
    1622             :   /// returns `joined_rooms`:
    1623             :   /// The ID of each room in which the user has `joined` membership.
    1624           0 :   Future<List<String>> getJoinedRooms() async {
    1625           0 :     final requestUri = Uri(path: '_matrix/client/v3/joined_rooms');
    1626           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1627           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1628           0 :     final response = await httpClient.send(request);
    1629           0 :     final responseBody = await response.stream.toBytes();
    1630           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1631           0 :     final responseString = utf8.decode(responseBody);
    1632           0 :     final json = jsonDecode(responseString);
    1633           0 :     return (json['joined_rooms'] as List).map((v) => v as String).toList();
    1634             :   }
    1635             : 
    1636             :   /// Gets a list of users who have updated their device identity keys since a
    1637             :   /// previous sync token.
    1638             :   ///
    1639             :   /// The server should include in the results any users who:
    1640             :   ///
    1641             :   /// * currently share a room with the calling user (ie, both users have
    1642             :   ///   membership state `join`); *and*
    1643             :   /// * added new device identity keys or removed an existing device with
    1644             :   ///   identity keys, between `from` and `to`.
    1645             :   ///
    1646             :   /// [from] The desired start point of the list. Should be the `next_batch` field
    1647             :   /// from a response to an earlier call to [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync). Users who have not
    1648             :   /// uploaded new device identity keys since this point, nor deleted
    1649             :   /// existing devices with identity keys since then, will be excluded
    1650             :   /// from the results.
    1651             :   ///
    1652             :   /// [to] The desired end point of the list. Should be the `next_batch`
    1653             :   /// field from a recent call to [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync) - typically the most recent
    1654             :   /// such call. This may be used by the server as a hint to check its
    1655             :   /// caches are up to date.
    1656           0 :   Future<GetKeysChangesResponse> getKeysChanges(String from, String to) async {
    1657             :     final requestUri =
    1658           0 :         Uri(path: '_matrix/client/v3/keys/changes', queryParameters: {
    1659             :       'from': from,
    1660             :       'to': to,
    1661             :     });
    1662           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1663           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1664           0 :     final response = await httpClient.send(request);
    1665           0 :     final responseBody = await response.stream.toBytes();
    1666           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1667           0 :     final responseString = utf8.decode(responseBody);
    1668           0 :     final json = jsonDecode(responseString);
    1669           0 :     return GetKeysChangesResponse.fromJson(json as Map<String, Object?>);
    1670             :   }
    1671             : 
    1672             :   /// Claims one-time keys for use in pre-key messages.
    1673             :   ///
    1674             :   /// [oneTimeKeys] The keys to be claimed. A map from user ID, to a map from
    1675             :   /// device ID to algorithm name.
    1676             :   ///
    1677             :   /// [timeout] The time (in milliseconds) to wait when downloading keys from
    1678             :   /// remote servers. 10 seconds is the recommended default.
    1679          10 :   Future<ClaimKeysResponse> claimKeys(
    1680             :       Map<String, Map<String, String>> oneTimeKeys,
    1681             :       {int? timeout}) async {
    1682          10 :     final requestUri = Uri(path: '_matrix/client/v3/keys/claim');
    1683          30 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1684          40 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1685          20 :     request.headers['content-type'] = 'application/json';
    1686          40 :     request.bodyBytes = utf8.encode(jsonEncode({
    1687          10 :       'one_time_keys': oneTimeKeys
    1688          60 :           .map((k, v) => MapEntry(k, v.map((k, v) => MapEntry(k, v)))),
    1689          10 :       if (timeout != null) 'timeout': timeout,
    1690             :     }));
    1691          20 :     final response = await httpClient.send(request);
    1692          20 :     final responseBody = await response.stream.toBytes();
    1693          20 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1694          10 :     final responseString = utf8.decode(responseBody);
    1695          10 :     final json = jsonDecode(responseString);
    1696          10 :     return ClaimKeysResponse.fromJson(json as Map<String, Object?>);
    1697             :   }
    1698             : 
    1699             :   /// Publishes cross-signing keys for the user.
    1700             :   ///
    1701             :   /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api).
    1702             :   ///
    1703             :   /// [auth] Additional authentication information for the
    1704             :   /// user-interactive authentication API.
    1705             :   ///
    1706             :   /// [masterKey] Optional. The user\'s master key.
    1707             :   ///
    1708             :   /// [selfSigningKey] Optional. The user\'s self-signing key. Must be signed by
    1709             :   /// the accompanying master key, or by the user\'s most recently
    1710             :   /// uploaded master key if no master key is included in the
    1711             :   /// request.
    1712             :   ///
    1713             :   /// [userSigningKey] Optional. The user\'s user-signing key. Must be signed by
    1714             :   /// the accompanying master key, or by the user\'s most recently
    1715             :   /// uploaded master key if no master key is included in the
    1716             :   /// request.
    1717           1 :   Future<void> uploadCrossSigningKeys(
    1718             :       {AuthenticationData? auth,
    1719             :       MatrixCrossSigningKey? masterKey,
    1720             :       MatrixCrossSigningKey? selfSigningKey,
    1721             :       MatrixCrossSigningKey? userSigningKey}) async {
    1722             :     final requestUri =
    1723           1 :         Uri(path: '_matrix/client/v3/keys/device_signing/upload');
    1724           3 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1725           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1726           2 :     request.headers['content-type'] = 'application/json';
    1727           4 :     request.bodyBytes = utf8.encode(jsonEncode({
    1728           0 :       if (auth != null) 'auth': auth.toJson(),
    1729           2 :       if (masterKey != null) 'master_key': masterKey.toJson(),
    1730           2 :       if (selfSigningKey != null) 'self_signing_key': selfSigningKey.toJson(),
    1731           2 :       if (userSigningKey != null) 'user_signing_key': userSigningKey.toJson(),
    1732             :     }));
    1733           2 :     final response = await httpClient.send(request);
    1734           2 :     final responseBody = await response.stream.toBytes();
    1735           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1736           1 :     final responseString = utf8.decode(responseBody);
    1737           1 :     final json = jsonDecode(responseString);
    1738           1 :     return ignore(json);
    1739             :   }
    1740             : 
    1741             :   /// Returns the current devices and identity keys for the given users.
    1742             :   ///
    1743             :   /// [deviceKeys] The keys to be downloaded. A map from user ID, to a list of
    1744             :   /// device IDs, or to an empty list to indicate all devices for the
    1745             :   /// corresponding user.
    1746             :   ///
    1747             :   /// [timeout] The time (in milliseconds) to wait when downloading keys from
    1748             :   /// remote servers. 10 seconds is the recommended default.
    1749             :   ///
    1750             :   /// [token] If the client is fetching keys as a result of a device update received
    1751             :   /// in a sync request, this should be the 'since' token of that sync request,
    1752             :   /// or any later sync token. This allows the server to ensure its response
    1753             :   /// contains the keys advertised by the notification in that sync.
    1754          30 :   Future<QueryKeysResponse> queryKeys(Map<String, List<String>> deviceKeys,
    1755             :       {int? timeout, String? token}) async {
    1756          30 :     final requestUri = Uri(path: '_matrix/client/v3/keys/query');
    1757          90 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1758         120 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1759          60 :     request.headers['content-type'] = 'application/json';
    1760         120 :     request.bodyBytes = utf8.encode(jsonEncode({
    1761          30 :       'device_keys':
    1762         150 :           deviceKeys.map((k, v) => MapEntry(k, v.map((v) => v).toList())),
    1763          29 :       if (timeout != null) 'timeout': timeout,
    1764           0 :       if (token != null) 'token': token,
    1765             :     }));
    1766          60 :     final response = await httpClient.send(request);
    1767          60 :     final responseBody = await response.stream.toBytes();
    1768          60 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1769          30 :     final responseString = utf8.decode(responseBody);
    1770          30 :     final json = jsonDecode(responseString);
    1771          30 :     return QueryKeysResponse.fromJson(json as Map<String, Object?>);
    1772             :   }
    1773             : 
    1774             :   /// Publishes cross-signing signatures for the user.  The request body is a
    1775             :   /// map from user ID to key ID to signed JSON object.
    1776             :   ///
    1777             :   /// [signatures] The signatures to be published.
    1778             :   ///
    1779             :   /// returns `failures`:
    1780             :   /// A map from user ID to key ID to an error for any signatures
    1781             :   /// that failed.  If a signature was invalid, the `errcode` will
    1782             :   /// be set to `M_INVALID_SIGNATURE`.
    1783           7 :   Future<Map<String, Map<String, Map<String, Object?>>>?>
    1784             :       uploadCrossSigningSignatures(
    1785             :           Map<String, Map<String, Map<String, Object?>>> signatures) async {
    1786           7 :     final requestUri = Uri(path: '_matrix/client/v3/keys/signatures/upload');
    1787          21 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1788          28 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1789          14 :     request.headers['content-type'] = 'application/json';
    1790          21 :     request.bodyBytes = utf8.encode(jsonEncode(signatures
    1791          42 :         .map((k, v) => MapEntry(k, v.map((k, v) => MapEntry(k, v))))));
    1792          14 :     final response = await httpClient.send(request);
    1793          14 :     final responseBody = await response.stream.toBytes();
    1794          14 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1795           7 :     final responseString = utf8.decode(responseBody);
    1796           7 :     final json = jsonDecode(responseString);
    1797           7 :     return ((v) => v != null
    1798           7 :         ? (v as Map<String, Object?>).map((k, v) => MapEntry(
    1799             :             k,
    1800             :             (v as Map<String, Object?>)
    1801           0 :                 .map((k, v) => MapEntry(k, v as Map<String, Object?>))))
    1802          14 :         : null)(json['failures']);
    1803             :   }
    1804             : 
    1805             :   /// *Note that this API takes either a room ID or alias, unlike other membership APIs.*
    1806             :   ///
    1807             :   /// This API "knocks" on the room to ask for permission to join, if the user
    1808             :   /// is allowed to knock on the room. Acceptance of the knock happens out of
    1809             :   /// band from this API, meaning that the client will have to watch for updates
    1810             :   /// regarding the acceptance/rejection of the knock.
    1811             :   ///
    1812             :   /// If the room history settings allow, the user will still be able to see
    1813             :   /// history of the room while being in the "knock" state. The user will have
    1814             :   /// to accept the invitation to join the room (acceptance of knock) to see
    1815             :   /// messages reliably. See the `/join` endpoints for more information about
    1816             :   /// history visibility to the user.
    1817             :   ///
    1818             :   /// The knock will appear as an entry in the response of the
    1819             :   /// [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync) API.
    1820             :   ///
    1821             :   /// [roomIdOrAlias] The room identifier or alias to knock upon.
    1822             :   ///
    1823             :   /// [serverName] The servers to attempt to knock on the room through. One of the servers
    1824             :   /// must be participating in the room.
    1825             :   ///
    1826             :   /// [reason] Optional reason to be included as the `reason` on the subsequent
    1827             :   /// membership event.
    1828             :   ///
    1829             :   /// returns `room_id`:
    1830             :   /// The knocked room ID.
    1831           0 :   Future<String> knockRoom(String roomIdOrAlias,
    1832             :       {List<String>? serverName, String? reason}) async {
    1833           0 :     final requestUri = Uri(
    1834           0 :         path: '_matrix/client/v3/knock/${Uri.encodeComponent(roomIdOrAlias)}',
    1835           0 :         queryParameters: {
    1836             :           if (serverName != null)
    1837           0 :             'server_name': serverName.map((v) => v).toList(),
    1838             :         });
    1839           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1840           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1841           0 :     request.headers['content-type'] = 'application/json';
    1842           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    1843           0 :       if (reason != null) 'reason': reason,
    1844             :     }));
    1845           0 :     final response = await httpClient.send(request);
    1846           0 :     final responseBody = await response.stream.toBytes();
    1847           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1848           0 :     final responseString = utf8.decode(responseBody);
    1849           0 :     final json = jsonDecode(responseString);
    1850           0 :     return json['room_id'] as String;
    1851             :   }
    1852             : 
    1853             :   /// Gets the homeserver's supported login types to authenticate users. Clients
    1854             :   /// should pick one of these and supply it as the `type` when logging in.
    1855             :   ///
    1856             :   /// returns `flows`:
    1857             :   /// The homeserver's supported login types
    1858          33 :   Future<List<LoginFlow>?> getLoginFlows() async {
    1859          33 :     final requestUri = Uri(path: '_matrix/client/v3/login');
    1860          99 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    1861          66 :     final response = await httpClient.send(request);
    1862          66 :     final responseBody = await response.stream.toBytes();
    1863          66 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1864          33 :     final responseString = utf8.decode(responseBody);
    1865          33 :     final json = jsonDecode(responseString);
    1866          33 :     return ((v) => v != null
    1867             :         ? (v as List)
    1868          99 :             .map((v) => LoginFlow.fromJson(v as Map<String, Object?>))
    1869          33 :             .toList()
    1870          66 :         : null)(json['flows']);
    1871             :   }
    1872             : 
    1873             :   /// Authenticates the user, and issues an access token they can
    1874             :   /// use to authorize themself in subsequent requests.
    1875             :   ///
    1876             :   /// If the client does not supply a `device_id`, the server must
    1877             :   /// auto-generate one.
    1878             :   ///
    1879             :   /// The returned access token must be associated with the `device_id`
    1880             :   /// supplied by the client or generated by the server. The server may
    1881             :   /// invalidate any access token previously associated with that device. See
    1882             :   /// [Relationship between access tokens and devices](https://spec.matrix.org/unstable/client-server-api/#relationship-between-access-tokens-and-devices).
    1883             :   ///
    1884             :   /// [address] Third party identifier for the user.  Deprecated in favour of `identifier`.
    1885             :   ///
    1886             :   /// [deviceId] ID of the client device. If this does not correspond to a
    1887             :   /// known client device, a new device will be created. The given
    1888             :   /// device ID must not be the same as a
    1889             :   /// [cross-signing](https://spec.matrix.org/unstable/client-server-api/#cross-signing) key ID.
    1890             :   /// The server will auto-generate a device_id
    1891             :   /// if this is not specified.
    1892             :   ///
    1893             :   /// [identifier] Identification information for a user
    1894             :   ///
    1895             :   /// [initialDeviceDisplayName] A display name to assign to the newly-created device. Ignored
    1896             :   /// if `device_id` corresponds to a known device.
    1897             :   ///
    1898             :   /// [medium] When logging in using a third party identifier, the medium of the identifier. Must be 'email'.  Deprecated in favour of `identifier`.
    1899             :   ///
    1900             :   /// [password] Required when `type` is `m.login.password`. The user's
    1901             :   /// password.
    1902             :   ///
    1903             :   /// [refreshToken] If true, the client supports refresh tokens.
    1904             :   ///
    1905             :   /// [token] Required when `type` is `m.login.token`. Part of Token-based login.
    1906             :   ///
    1907             :   /// [type] The login type being used.
    1908             :   ///
    1909             :   /// [user] The fully qualified user ID or just local part of the user ID, to log in.  Deprecated in favour of `identifier`.
    1910           4 :   Future<LoginResponse> login(LoginType type,
    1911             :       {String? address,
    1912             :       String? deviceId,
    1913             :       AuthenticationIdentifier? identifier,
    1914             :       String? initialDeviceDisplayName,
    1915             :       String? medium,
    1916             :       String? password,
    1917             :       bool? refreshToken,
    1918             :       String? token,
    1919             :       String? user}) async {
    1920           4 :     final requestUri = Uri(path: '_matrix/client/v3/login');
    1921          12 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1922           8 :     request.headers['content-type'] = 'application/json';
    1923          16 :     request.bodyBytes = utf8.encode(jsonEncode({
    1924           0 :       if (address != null) 'address': address,
    1925           0 :       if (deviceId != null) 'device_id': deviceId,
    1926           8 :       if (identifier != null) 'identifier': identifier.toJson(),
    1927             :       if (initialDeviceDisplayName != null)
    1928           0 :         'initial_device_display_name': initialDeviceDisplayName,
    1929           0 :       if (medium != null) 'medium': medium,
    1930           4 :       if (password != null) 'password': password,
    1931           4 :       if (refreshToken != null) 'refresh_token': refreshToken,
    1932           0 :       if (token != null) 'token': token,
    1933           8 :       'type': type.name,
    1934           0 :       if (user != null) 'user': user,
    1935             :     }));
    1936           8 :     final response = await httpClient.send(request);
    1937           8 :     final responseBody = await response.stream.toBytes();
    1938           8 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1939           4 :     final responseString = utf8.decode(responseBody);
    1940           4 :     final json = jsonDecode(responseString);
    1941           4 :     return LoginResponse.fromJson(json as Map<String, Object?>);
    1942             :   }
    1943             : 
    1944             :   /// Invalidates an existing access token, so that it can no longer be used for
    1945             :   /// authorization. The device associated with the access token is also deleted.
    1946             :   /// [Device keys](https://spec.matrix.org/unstable/client-server-api/#device-keys) for the device are deleted alongside the device.
    1947           9 :   Future<void> logout() async {
    1948           9 :     final requestUri = Uri(path: '_matrix/client/v3/logout');
    1949          27 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1950          36 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1951          18 :     final response = await httpClient.send(request);
    1952          18 :     final responseBody = await response.stream.toBytes();
    1953          19 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1954           9 :     final responseString = utf8.decode(responseBody);
    1955           9 :     final json = jsonDecode(responseString);
    1956           9 :     return ignore(json);
    1957             :   }
    1958             : 
    1959             :   /// Invalidates all access tokens for a user, so that they can no longer be used for
    1960             :   /// authorization. This includes the access token that made this request. All devices
    1961             :   /// for the user are also deleted. [Device keys](https://spec.matrix.org/unstable/client-server-api/#device-keys) for the device are
    1962             :   /// deleted alongside the device.
    1963             :   ///
    1964             :   /// This endpoint does not use the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api) because
    1965             :   /// User-Interactive Authentication is designed to protect against attacks where the
    1966             :   /// someone gets hold of a single access token then takes over the account. This
    1967             :   /// endpoint invalidates all access tokens for the user, including the token used in
    1968             :   /// the request, and therefore the attacker is unable to take over the account in
    1969             :   /// this way.
    1970           0 :   Future<void> logoutAll() async {
    1971           0 :     final requestUri = Uri(path: '_matrix/client/v3/logout/all');
    1972           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    1973           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    1974           0 :     final response = await httpClient.send(request);
    1975           0 :     final responseBody = await response.stream.toBytes();
    1976           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    1977           0 :     final responseString = utf8.decode(responseBody);
    1978           0 :     final json = jsonDecode(responseString);
    1979           0 :     return ignore(json);
    1980             :   }
    1981             : 
    1982             :   /// This API is used to paginate through the list of events that the
    1983             :   /// user has been, or would have been notified about.
    1984             :   ///
    1985             :   /// [from] Pagination token to continue from. This should be the `next_token`
    1986             :   /// returned from an earlier call to this endpoint.
    1987             :   ///
    1988             :   /// [limit] Limit on the number of events to return in this request.
    1989             :   ///
    1990             :   /// [only] Allows basic filtering of events returned. Supply `highlight`
    1991             :   /// to return only events where the notification had the highlight
    1992             :   /// tweak set.
    1993           0 :   Future<GetNotificationsResponse> getNotifications(
    1994             :       {String? from, int? limit, String? only}) async {
    1995             :     final requestUri =
    1996           0 :         Uri(path: '_matrix/client/v3/notifications', queryParameters: {
    1997           0 :       if (from != null) 'from': from,
    1998           0 :       if (limit != null) 'limit': limit.toString(),
    1999           0 :       if (only != null) 'only': only,
    2000             :     });
    2001           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2002           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2003           0 :     final response = await httpClient.send(request);
    2004           0 :     final responseBody = await response.stream.toBytes();
    2005           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2006           0 :     final responseString = utf8.decode(responseBody);
    2007           0 :     final json = jsonDecode(responseString);
    2008           0 :     return GetNotificationsResponse.fromJson(json as Map<String, Object?>);
    2009             :   }
    2010             : 
    2011             :   /// Get the given user's presence state.
    2012             :   ///
    2013             :   /// [userId] The user whose presence state to get.
    2014           0 :   Future<GetPresenceResponse> getPresence(String userId) async {
    2015           0 :     final requestUri = Uri(
    2016             :         path:
    2017           0 :             '_matrix/client/v3/presence/${Uri.encodeComponent(userId)}/status');
    2018           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2019           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2020           0 :     final response = await httpClient.send(request);
    2021           0 :     final responseBody = await response.stream.toBytes();
    2022           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2023           0 :     final responseString = utf8.decode(responseBody);
    2024           0 :     final json = jsonDecode(responseString);
    2025           0 :     return GetPresenceResponse.fromJson(json as Map<String, Object?>);
    2026             :   }
    2027             : 
    2028             :   /// This API sets the given user's presence state. When setting the status,
    2029             :   /// the activity time is updated to reflect that activity; the client does
    2030             :   /// not need to specify the `last_active_ago` field. You cannot set the
    2031             :   /// presence state of another user.
    2032             :   ///
    2033             :   /// [userId] The user whose presence state to update.
    2034             :   ///
    2035             :   /// [presence] The new presence state.
    2036             :   ///
    2037             :   /// [statusMsg] The status message to attach to this state.
    2038           0 :   Future<void> setPresence(String userId, PresenceType presence,
    2039             :       {String? statusMsg}) async {
    2040           0 :     final requestUri = Uri(
    2041             :         path:
    2042           0 :             '_matrix/client/v3/presence/${Uri.encodeComponent(userId)}/status');
    2043           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    2044           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2045           0 :     request.headers['content-type'] = 'application/json';
    2046           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    2047           0 :       'presence': presence.name,
    2048           0 :       if (statusMsg != null) 'status_msg': statusMsg,
    2049             :     }));
    2050           0 :     final response = await httpClient.send(request);
    2051           0 :     final responseBody = await response.stream.toBytes();
    2052           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2053           0 :     final responseString = utf8.decode(responseBody);
    2054           0 :     final json = jsonDecode(responseString);
    2055           0 :     return ignore(json);
    2056             :   }
    2057             : 
    2058             :   /// Get the combined profile information for this user. This API may be used
    2059             :   /// to fetch the user's own profile information or other users; either
    2060             :   /// locally or on remote homeservers. This API may return keys which are not
    2061             :   /// limited to `displayname` or `avatar_url`.
    2062             :   ///
    2063             :   /// [userId] The user whose profile information to get.
    2064           4 :   Future<ProfileInformation> getUserProfile(String userId) async {
    2065             :     final requestUri =
    2066          12 :         Uri(path: '_matrix/client/v3/profile/${Uri.encodeComponent(userId)}');
    2067          10 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2068           6 :     final response = await httpClient.send(request);
    2069           6 :     final responseBody = await response.stream.toBytes();
    2070           7 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2071           3 :     final responseString = utf8.decode(responseBody);
    2072           3 :     final json = jsonDecode(responseString);
    2073           3 :     return ProfileInformation.fromJson(json as Map<String, Object?>);
    2074             :   }
    2075             : 
    2076             :   /// Get the user's avatar URL. This API may be used to fetch the user's
    2077             :   /// own avatar URL or to query the URL of other users; either locally or
    2078             :   /// on remote homeservers.
    2079             :   ///
    2080             :   /// [userId] The user whose avatar URL to get.
    2081             :   ///
    2082             :   /// returns `avatar_url`:
    2083             :   /// The user's avatar URL if they have set one, otherwise not present.
    2084           0 :   Future<Uri?> getAvatarUrl(String userId) async {
    2085           0 :     final requestUri = Uri(
    2086             :         path:
    2087           0 :             '_matrix/client/v3/profile/${Uri.encodeComponent(userId)}/avatar_url');
    2088           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2089           0 :     final response = await httpClient.send(request);
    2090           0 :     final responseBody = await response.stream.toBytes();
    2091           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2092           0 :     final responseString = utf8.decode(responseBody);
    2093           0 :     final json = jsonDecode(responseString);
    2094           0 :     return ((v) =>
    2095           0 :         v != null ? Uri.parse(v as String) : null)(json['avatar_url']);
    2096             :   }
    2097             : 
    2098             :   /// This API sets the given user's avatar URL. You must have permission to
    2099             :   /// set this user's avatar URL, e.g. you need to have their `access_token`.
    2100             :   ///
    2101             :   /// [userId] The user whose avatar URL to set.
    2102             :   ///
    2103             :   /// [avatarUrl] The new avatar URL for this user.
    2104           1 :   Future<void> setAvatarUrl(String userId, Uri? avatarUrl) async {
    2105           1 :     final requestUri = Uri(
    2106             :         path:
    2107           2 :             '_matrix/client/v3/profile/${Uri.encodeComponent(userId)}/avatar_url');
    2108           3 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    2109           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2110           2 :     request.headers['content-type'] = 'application/json';
    2111           4 :     request.bodyBytes = utf8.encode(jsonEncode({
    2112           2 :       if (avatarUrl != null) 'avatar_url': avatarUrl.toString(),
    2113             :     }));
    2114           2 :     final response = await httpClient.send(request);
    2115           2 :     final responseBody = await response.stream.toBytes();
    2116           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2117           1 :     final responseString = utf8.decode(responseBody);
    2118           1 :     final json = jsonDecode(responseString);
    2119           1 :     return ignore(json);
    2120             :   }
    2121             : 
    2122             :   /// Get the user's display name. This API may be used to fetch the user's
    2123             :   /// own displayname or to query the name of other users; either locally or
    2124             :   /// on remote homeservers.
    2125             :   ///
    2126             :   /// [userId] The user whose display name to get.
    2127             :   ///
    2128             :   /// returns `displayname`:
    2129             :   /// The user's display name if they have set one, otherwise not present.
    2130           0 :   Future<String?> getDisplayName(String userId) async {
    2131           0 :     final requestUri = Uri(
    2132             :         path:
    2133           0 :             '_matrix/client/v3/profile/${Uri.encodeComponent(userId)}/displayname');
    2134           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2135           0 :     final response = await httpClient.send(request);
    2136           0 :     final responseBody = await response.stream.toBytes();
    2137           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2138           0 :     final responseString = utf8.decode(responseBody);
    2139           0 :     final json = jsonDecode(responseString);
    2140           0 :     return ((v) => v != null ? v as String : null)(json['displayname']);
    2141             :   }
    2142             : 
    2143             :   /// This API sets the given user's display name. You must have permission to
    2144             :   /// set this user's display name, e.g. you need to have their `access_token`.
    2145             :   ///
    2146             :   /// [userId] The user whose display name to set.
    2147             :   ///
    2148             :   /// [displayname] The new display name for this user.
    2149           0 :   Future<void> setDisplayName(String userId, String? displayname) async {
    2150           0 :     final requestUri = Uri(
    2151             :         path:
    2152           0 :             '_matrix/client/v3/profile/${Uri.encodeComponent(userId)}/displayname');
    2153           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    2154           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2155           0 :     request.headers['content-type'] = 'application/json';
    2156           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    2157           0 :       if (displayname != null) 'displayname': displayname,
    2158             :     }));
    2159           0 :     final response = await httpClient.send(request);
    2160           0 :     final responseBody = await response.stream.toBytes();
    2161           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2162           0 :     final responseString = utf8.decode(responseBody);
    2163           0 :     final json = jsonDecode(responseString);
    2164           0 :     return ignore(json);
    2165             :   }
    2166             : 
    2167             :   /// Lists the public rooms on the server.
    2168             :   ///
    2169             :   /// This API returns paginated responses. The rooms are ordered by the number
    2170             :   /// of joined members, with the largest rooms first.
    2171             :   ///
    2172             :   /// [limit] Limit the number of results returned.
    2173             :   ///
    2174             :   /// [since] A pagination token from a previous request, allowing clients to
    2175             :   /// get the next (or previous) batch of rooms.
    2176             :   /// The direction of pagination is specified solely by which token
    2177             :   /// is supplied, rather than via an explicit flag.
    2178             :   ///
    2179             :   /// [server] The server to fetch the public room lists from. Defaults to the
    2180             :   /// local server.
    2181           0 :   Future<GetPublicRoomsResponse> getPublicRooms(
    2182             :       {int? limit, String? since, String? server}) async {
    2183             :     final requestUri =
    2184           0 :         Uri(path: '_matrix/client/v3/publicRooms', queryParameters: {
    2185           0 :       if (limit != null) 'limit': limit.toString(),
    2186           0 :       if (since != null) 'since': since,
    2187           0 :       if (server != null) 'server': server,
    2188             :     });
    2189           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2190           0 :     final response = await httpClient.send(request);
    2191           0 :     final responseBody = await response.stream.toBytes();
    2192           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2193           0 :     final responseString = utf8.decode(responseBody);
    2194           0 :     final json = jsonDecode(responseString);
    2195           0 :     return GetPublicRoomsResponse.fromJson(json as Map<String, Object?>);
    2196             :   }
    2197             : 
    2198             :   /// Lists the public rooms on the server, with optional filter.
    2199             :   ///
    2200             :   /// This API returns paginated responses. The rooms are ordered by the number
    2201             :   /// of joined members, with the largest rooms first.
    2202             :   ///
    2203             :   /// [server] The server to fetch the public room lists from. Defaults to the
    2204             :   /// local server.
    2205             :   ///
    2206             :   /// [filter] Filter to apply to the results.
    2207             :   ///
    2208             :   /// [includeAllNetworks] Whether or not to include all known networks/protocols from
    2209             :   /// application services on the homeserver. Defaults to false.
    2210             :   ///
    2211             :   /// [limit] Limit the number of results returned.
    2212             :   ///
    2213             :   /// [since] A pagination token from a previous request, allowing clients
    2214             :   /// to get the next (or previous) batch of rooms.  The direction
    2215             :   /// of pagination is specified solely by which token is supplied,
    2216             :   /// rather than via an explicit flag.
    2217             :   ///
    2218             :   /// [thirdPartyInstanceId] The specific third party network/protocol to request from the
    2219             :   /// homeserver. Can only be used if `include_all_networks` is false.
    2220           0 :   Future<QueryPublicRoomsResponse> queryPublicRooms(
    2221             :       {String? server,
    2222             :       PublicRoomQueryFilter? filter,
    2223             :       bool? includeAllNetworks,
    2224             :       int? limit,
    2225             :       String? since,
    2226             :       String? thirdPartyInstanceId}) async {
    2227             :     final requestUri =
    2228           0 :         Uri(path: '_matrix/client/v3/publicRooms', queryParameters: {
    2229           0 :       if (server != null) 'server': server,
    2230             :     });
    2231           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    2232           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2233           0 :     request.headers['content-type'] = 'application/json';
    2234           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    2235           0 :       if (filter != null) 'filter': filter.toJson(),
    2236             :       if (includeAllNetworks != null)
    2237           0 :         'include_all_networks': includeAllNetworks,
    2238           0 :       if (limit != null) 'limit': limit,
    2239           0 :       if (since != null) 'since': since,
    2240             :       if (thirdPartyInstanceId != null)
    2241           0 :         'third_party_instance_id': thirdPartyInstanceId,
    2242             :     }));
    2243           0 :     final response = await httpClient.send(request);
    2244           0 :     final responseBody = await response.stream.toBytes();
    2245           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2246           0 :     final responseString = utf8.decode(responseBody);
    2247           0 :     final json = jsonDecode(responseString);
    2248           0 :     return QueryPublicRoomsResponse.fromJson(json as Map<String, Object?>);
    2249             :   }
    2250             : 
    2251             :   /// Gets all currently active pushers for the authenticated user.
    2252             :   ///
    2253             :   /// returns `pushers`:
    2254             :   /// An array containing the current pushers for the user
    2255           0 :   Future<List<Pusher>?> getPushers() async {
    2256           0 :     final requestUri = Uri(path: '_matrix/client/v3/pushers');
    2257           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2258           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2259           0 :     final response = await httpClient.send(request);
    2260           0 :     final responseBody = await response.stream.toBytes();
    2261           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2262           0 :     final responseString = utf8.decode(responseBody);
    2263           0 :     final json = jsonDecode(responseString);
    2264           0 :     return ((v) => v != null
    2265             :         ? (v as List)
    2266           0 :             .map((v) => Pusher.fromJson(v as Map<String, Object?>))
    2267           0 :             .toList()
    2268           0 :         : null)(json['pushers']);
    2269             :   }
    2270             : 
    2271             :   /// Retrieve all push rulesets for this user. Clients can "drill-down" on
    2272             :   /// the rulesets by suffixing a `scope` to this path e.g.
    2273             :   /// `/pushrules/global/`. This will return a subset of this data under the
    2274             :   /// specified key e.g. the `global` key.
    2275             :   ///
    2276             :   /// returns `global`:
    2277             :   /// The global ruleset.
    2278           0 :   Future<PushRuleSet> getPushRules() async {
    2279           0 :     final requestUri = Uri(path: '_matrix/client/v3/pushrules/');
    2280           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2281           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2282           0 :     final response = await httpClient.send(request);
    2283           0 :     final responseBody = await response.stream.toBytes();
    2284           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2285           0 :     final responseString = utf8.decode(responseBody);
    2286           0 :     final json = jsonDecode(responseString);
    2287           0 :     return PushRuleSet.fromJson(json['global'] as Map<String, Object?>);
    2288             :   }
    2289             : 
    2290             :   /// This endpoint removes the push rule defined in the path.
    2291             :   ///
    2292             :   /// [scope] `global` to specify global rules.
    2293             :   ///
    2294             :   /// [kind] The kind of rule
    2295             :   ///
    2296             :   ///
    2297             :   /// [ruleId] The identifier for the rule.
    2298             :   ///
    2299           2 :   Future<void> deletePushRule(
    2300             :       String scope, PushRuleKind kind, String ruleId) async {
    2301           2 :     final requestUri = Uri(
    2302             :         path:
    2303          10 :             '_matrix/client/v3/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.name)}/${Uri.encodeComponent(ruleId)}');
    2304           6 :     final request = Request('DELETE', baseUri!.resolveUri(requestUri));
    2305           8 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2306           4 :     final response = await httpClient.send(request);
    2307           4 :     final responseBody = await response.stream.toBytes();
    2308           4 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2309           2 :     final responseString = utf8.decode(responseBody);
    2310           2 :     final json = jsonDecode(responseString);
    2311           2 :     return ignore(json);
    2312             :   }
    2313             : 
    2314             :   /// Retrieve a single specified push rule.
    2315             :   ///
    2316             :   /// [scope] `global` to specify global rules.
    2317             :   ///
    2318             :   /// [kind] The kind of rule
    2319             :   ///
    2320             :   ///
    2321             :   /// [ruleId] The identifier for the rule.
    2322             :   ///
    2323           0 :   Future<PushRule> getPushRule(
    2324             :       String scope, PushRuleKind kind, String ruleId) async {
    2325           0 :     final requestUri = Uri(
    2326             :         path:
    2327           0 :             '_matrix/client/v3/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.name)}/${Uri.encodeComponent(ruleId)}');
    2328           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2329           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2330           0 :     final response = await httpClient.send(request);
    2331           0 :     final responseBody = await response.stream.toBytes();
    2332           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2333           0 :     final responseString = utf8.decode(responseBody);
    2334           0 :     final json = jsonDecode(responseString);
    2335           0 :     return PushRule.fromJson(json as Map<String, Object?>);
    2336             :   }
    2337             : 
    2338             :   /// This endpoint allows the creation and modification of user defined push
    2339             :   /// rules.
    2340             :   ///
    2341             :   /// If a rule with the same `rule_id` already exists among rules of the same
    2342             :   /// kind, it is updated with the new parameters, otherwise a new rule is
    2343             :   /// created.
    2344             :   ///
    2345             :   /// If both `after` and `before` are provided, the new or updated rule must
    2346             :   /// be the next most important rule with respect to the rule identified by
    2347             :   /// `before`.
    2348             :   ///
    2349             :   /// If neither `after` nor `before` are provided and the rule is created, it
    2350             :   /// should be added as the most important user defined rule among rules of
    2351             :   /// the same kind.
    2352             :   ///
    2353             :   /// When creating push rules, they MUST be enabled by default.
    2354             :   ///
    2355             :   /// [scope] `global` to specify global rules.
    2356             :   ///
    2357             :   /// [kind] The kind of rule
    2358             :   ///
    2359             :   ///
    2360             :   /// [ruleId] The identifier for the rule. If the string starts with a dot ("."),
    2361             :   /// the request MUST be rejected as this is reserved for server-default
    2362             :   /// rules. Slashes ("/") and backslashes ("\\") are also not allowed.
    2363             :   ///
    2364             :   ///
    2365             :   /// [before] Use 'before' with a `rule_id` as its value to make the new rule the
    2366             :   /// next-most important rule with respect to the given user defined rule.
    2367             :   /// It is not possible to add a rule relative to a predefined server rule.
    2368             :   ///
    2369             :   /// [after] This makes the new rule the next-less important rule relative to the
    2370             :   /// given user defined rule. It is not possible to add a rule relative
    2371             :   /// to a predefined server rule.
    2372             :   ///
    2373             :   /// [actions] The action(s) to perform when the conditions for this rule are met.
    2374             :   ///
    2375             :   /// [conditions] The conditions that must hold true for an event in order for a
    2376             :   /// rule to be applied to an event. A rule with no conditions
    2377             :   /// always matches. Only applicable to `underride` and `override` rules.
    2378             :   ///
    2379             :   /// [pattern] Only applicable to `content` rules. The glob-style pattern to match against.
    2380           2 :   Future<void> setPushRule(
    2381             :       String scope, PushRuleKind kind, String ruleId, List<Object?> actions,
    2382             :       {String? before,
    2383             :       String? after,
    2384             :       List<PushCondition>? conditions,
    2385             :       String? pattern}) async {
    2386           2 :     final requestUri = Uri(
    2387             :         path:
    2388          10 :             '_matrix/client/v3/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.name)}/${Uri.encodeComponent(ruleId)}',
    2389           2 :         queryParameters: {
    2390           0 :           if (before != null) 'before': before,
    2391           0 :           if (after != null) 'after': after,
    2392             :         });
    2393           6 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    2394           8 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2395           4 :     request.headers['content-type'] = 'application/json';
    2396           8 :     request.bodyBytes = utf8.encode(jsonEncode({
    2397           8 :       'actions': actions.map((v) => v).toList(),
    2398             :       if (conditions != null)
    2399           0 :         'conditions': conditions.map((v) => v.toJson()).toList(),
    2400           0 :       if (pattern != null) 'pattern': pattern,
    2401             :     }));
    2402           4 :     final response = await httpClient.send(request);
    2403           4 :     final responseBody = await response.stream.toBytes();
    2404           4 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2405           2 :     final responseString = utf8.decode(responseBody);
    2406           2 :     final json = jsonDecode(responseString);
    2407           2 :     return ignore(json);
    2408             :   }
    2409             : 
    2410             :   /// This endpoint get the actions for the specified push rule.
    2411             :   ///
    2412             :   /// [scope] Either `global` or `device/<profile_tag>` to specify global
    2413             :   /// rules or device rules for the given `profile_tag`.
    2414             :   ///
    2415             :   /// [kind] The kind of rule
    2416             :   ///
    2417             :   ///
    2418             :   /// [ruleId] The identifier for the rule.
    2419             :   ///
    2420             :   ///
    2421             :   /// returns `actions`:
    2422             :   /// The action(s) to perform for this rule.
    2423           0 :   Future<List<Object?>> getPushRuleActions(
    2424             :       String scope, PushRuleKind kind, String ruleId) async {
    2425           0 :     final requestUri = Uri(
    2426             :         path:
    2427           0 :             '_matrix/client/v3/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.name)}/${Uri.encodeComponent(ruleId)}/actions');
    2428           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2429           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2430           0 :     final response = await httpClient.send(request);
    2431           0 :     final responseBody = await response.stream.toBytes();
    2432           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2433           0 :     final responseString = utf8.decode(responseBody);
    2434           0 :     final json = jsonDecode(responseString);
    2435           0 :     return (json['actions'] as List).map((v) => v as Object?).toList();
    2436             :   }
    2437             : 
    2438             :   /// This endpoint allows clients to change the actions of a push rule.
    2439             :   /// This can be used to change the actions of builtin rules.
    2440             :   ///
    2441             :   /// [scope] `global` to specify global rules.
    2442             :   ///
    2443             :   /// [kind] The kind of rule
    2444             :   ///
    2445             :   ///
    2446             :   /// [ruleId] The identifier for the rule.
    2447             :   ///
    2448             :   ///
    2449             :   /// [actions] The action(s) to perform for this rule.
    2450           0 :   Future<void> setPushRuleActions(String scope, PushRuleKind kind,
    2451             :       String ruleId, List<Object?> actions) async {
    2452           0 :     final requestUri = Uri(
    2453             :         path:
    2454           0 :             '_matrix/client/v3/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.name)}/${Uri.encodeComponent(ruleId)}/actions');
    2455           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    2456           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2457           0 :     request.headers['content-type'] = 'application/json';
    2458           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    2459           0 :       'actions': actions.map((v) => v).toList(),
    2460             :     }));
    2461           0 :     final response = await httpClient.send(request);
    2462           0 :     final responseBody = await response.stream.toBytes();
    2463           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2464           0 :     final responseString = utf8.decode(responseBody);
    2465           0 :     final json = jsonDecode(responseString);
    2466           0 :     return ignore(json);
    2467             :   }
    2468             : 
    2469             :   /// This endpoint gets whether the specified push rule is enabled.
    2470             :   ///
    2471             :   /// [scope] Either `global` or `device/<profile_tag>` to specify global
    2472             :   /// rules or device rules for the given `profile_tag`.
    2473             :   ///
    2474             :   /// [kind] The kind of rule
    2475             :   ///
    2476             :   ///
    2477             :   /// [ruleId] The identifier for the rule.
    2478             :   ///
    2479             :   ///
    2480             :   /// returns `enabled`:
    2481             :   /// Whether the push rule is enabled or not.
    2482           0 :   Future<bool> isPushRuleEnabled(
    2483             :       String scope, PushRuleKind kind, String ruleId) async {
    2484           0 :     final requestUri = Uri(
    2485             :         path:
    2486           0 :             '_matrix/client/v3/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.name)}/${Uri.encodeComponent(ruleId)}/enabled');
    2487           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2488           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2489           0 :     final response = await httpClient.send(request);
    2490           0 :     final responseBody = await response.stream.toBytes();
    2491           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2492           0 :     final responseString = utf8.decode(responseBody);
    2493           0 :     final json = jsonDecode(responseString);
    2494           0 :     return json['enabled'] as bool;
    2495             :   }
    2496             : 
    2497             :   /// This endpoint allows clients to enable or disable the specified push rule.
    2498             :   ///
    2499             :   /// [scope] `global` to specify global rules.
    2500             :   ///
    2501             :   /// [kind] The kind of rule
    2502             :   ///
    2503             :   ///
    2504             :   /// [ruleId] The identifier for the rule.
    2505             :   ///
    2506             :   ///
    2507             :   /// [enabled] Whether the push rule is enabled or not.
    2508           1 :   Future<void> setPushRuleEnabled(
    2509             :       String scope, PushRuleKind kind, String ruleId, bool enabled) async {
    2510           1 :     final requestUri = Uri(
    2511             :         path:
    2512           5 :             '_matrix/client/v3/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.name)}/${Uri.encodeComponent(ruleId)}/enabled');
    2513           3 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    2514           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2515           2 :     request.headers['content-type'] = 'application/json';
    2516           4 :     request.bodyBytes = utf8.encode(jsonEncode({
    2517             :       'enabled': enabled,
    2518             :     }));
    2519           2 :     final response = await httpClient.send(request);
    2520           2 :     final responseBody = await response.stream.toBytes();
    2521           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2522           1 :     final responseString = utf8.decode(responseBody);
    2523           1 :     final json = jsonDecode(responseString);
    2524           1 :     return ignore(json);
    2525             :   }
    2526             : 
    2527             :   /// Refresh an access token. Clients should use the returned access token
    2528             :   /// when making subsequent API calls, and store the returned refresh token
    2529             :   /// (if given) in order to refresh the new access token when necessary.
    2530             :   ///
    2531             :   /// After an access token has been refreshed, a server can choose to
    2532             :   /// invalidate the old access token immediately, or can choose not to, for
    2533             :   /// example if the access token would expire soon anyways. Clients should
    2534             :   /// not make any assumptions about the old access token still being valid,
    2535             :   /// and should use the newly provided access token instead.
    2536             :   ///
    2537             :   /// The old refresh token remains valid until the new access token or refresh token
    2538             :   /// is used, at which point the old refresh token is revoked.
    2539             :   ///
    2540             :   /// Note that this endpoint does not require authentication via an
    2541             :   /// access token. Authentication is provided via the refresh token.
    2542             :   ///
    2543             :   /// Application Service identity assertion is disabled for this endpoint.
    2544             :   ///
    2545             :   /// [refreshToken] The refresh token
    2546           0 :   Future<RefreshResponse> refresh(String refreshToken) async {
    2547           0 :     final requestUri = Uri(path: '_matrix/client/v3/refresh');
    2548           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    2549           0 :     request.headers['content-type'] = 'application/json';
    2550           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    2551             :       'refresh_token': refreshToken,
    2552             :     }));
    2553           0 :     final response = await httpClient.send(request);
    2554           0 :     final responseBody = await response.stream.toBytes();
    2555           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2556           0 :     final responseString = utf8.decode(responseBody);
    2557           0 :     final json = jsonDecode(responseString);
    2558           0 :     return RefreshResponse.fromJson(json as Map<String, Object?>);
    2559             :   }
    2560             : 
    2561             :   /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api), except in
    2562             :   /// the cases where a guest account is being registered.
    2563             :   ///
    2564             :   /// Register for an account on this homeserver.
    2565             :   ///
    2566             :   /// There are two kinds of user account:
    2567             :   ///
    2568             :   /// - `user` accounts. These accounts may use the full API described in this specification.
    2569             :   ///
    2570             :   /// - `guest` accounts. These accounts may have limited permissions and may not be supported by all servers.
    2571             :   ///
    2572             :   /// If registration is successful, this endpoint will issue an access token
    2573             :   /// the client can use to authorize itself in subsequent requests.
    2574             :   ///
    2575             :   /// If the client does not supply a `device_id`, the server must
    2576             :   /// auto-generate one.
    2577             :   ///
    2578             :   /// The server SHOULD register an account with a User ID based on the
    2579             :   /// `username` provided, if any. Note that the grammar of Matrix User ID
    2580             :   /// localparts is restricted, so the server MUST either map the provided
    2581             :   /// `username` onto a `user_id` in a logical manner, or reject
    2582             :   /// `username`\s which do not comply to the grammar, with
    2583             :   /// `M_INVALID_USERNAME`.
    2584             :   ///
    2585             :   /// Matrix clients MUST NOT assume that localpart of the registered
    2586             :   /// `user_id` matches the provided `username`.
    2587             :   ///
    2588             :   /// The returned access token must be associated with the `device_id`
    2589             :   /// supplied by the client or generated by the server. The server may
    2590             :   /// invalidate any access token previously associated with that device. See
    2591             :   /// [Relationship between access tokens and devices](https://spec.matrix.org/unstable/client-server-api/#relationship-between-access-tokens-and-devices).
    2592             :   ///
    2593             :   /// When registering a guest account, all parameters in the request body
    2594             :   /// with the exception of `initial_device_display_name` MUST BE ignored
    2595             :   /// by the server. The server MUST pick a `device_id` for the account
    2596             :   /// regardless of input.
    2597             :   ///
    2598             :   /// Any user ID returned by this API must conform to the grammar given in the
    2599             :   /// [Matrix specification](https://spec.matrix.org/unstable/appendices/#user-identifiers).
    2600             :   ///
    2601             :   /// [kind] The kind of account to register. Defaults to `user`.
    2602             :   ///
    2603             :   /// [auth] Additional authentication information for the
    2604             :   /// user-interactive authentication API. Note that this
    2605             :   /// information is *not* used to define how the registered user
    2606             :   /// should be authenticated, but is instead used to
    2607             :   /// authenticate the `register` call itself.
    2608             :   ///
    2609             :   /// [deviceId] ID of the client device. If this does not correspond to a
    2610             :   /// known client device, a new device will be created. The server
    2611             :   /// will auto-generate a device_id if this is not specified.
    2612             :   ///
    2613             :   /// [inhibitLogin] If true, an `access_token` and `device_id` should not be
    2614             :   /// returned from this call, therefore preventing an automatic
    2615             :   /// login. Defaults to false.
    2616             :   ///
    2617             :   /// [initialDeviceDisplayName] A display name to assign to the newly-created device. Ignored
    2618             :   /// if `device_id` corresponds to a known device.
    2619             :   ///
    2620             :   /// [password] The desired password for the account.
    2621             :   ///
    2622             :   /// [refreshToken] If true, the client supports refresh tokens.
    2623             :   ///
    2624             :   /// [username] The basis for the localpart of the desired Matrix ID. If omitted,
    2625             :   /// the homeserver MUST generate a Matrix ID local part.
    2626           0 :   Future<RegisterResponse> register(
    2627             :       {AccountKind? kind,
    2628             :       AuthenticationData? auth,
    2629             :       String? deviceId,
    2630             :       bool? inhibitLogin,
    2631             :       String? initialDeviceDisplayName,
    2632             :       String? password,
    2633             :       bool? refreshToken,
    2634             :       String? username}) async {
    2635             :     final requestUri =
    2636           0 :         Uri(path: '_matrix/client/v3/register', queryParameters: {
    2637           0 :       if (kind != null) 'kind': kind.name,
    2638             :     });
    2639           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    2640           0 :     request.headers['content-type'] = 'application/json';
    2641           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    2642           0 :       if (auth != null) 'auth': auth.toJson(),
    2643           0 :       if (deviceId != null) 'device_id': deviceId,
    2644           0 :       if (inhibitLogin != null) 'inhibit_login': inhibitLogin,
    2645             :       if (initialDeviceDisplayName != null)
    2646           0 :         'initial_device_display_name': initialDeviceDisplayName,
    2647           0 :       if (password != null) 'password': password,
    2648           0 :       if (refreshToken != null) 'refresh_token': refreshToken,
    2649           0 :       if (username != null) 'username': username,
    2650             :     }));
    2651           0 :     final response = await httpClient.send(request);
    2652           0 :     final responseBody = await response.stream.toBytes();
    2653           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2654           0 :     final responseString = utf8.decode(responseBody);
    2655           0 :     final json = jsonDecode(responseString);
    2656           0 :     return RegisterResponse.fromJson(json as Map<String, Object?>);
    2657             :   }
    2658             : 
    2659             :   /// Checks to see if a username is available, and valid, for the server.
    2660             :   ///
    2661             :   /// The server should check to ensure that, at the time of the request, the
    2662             :   /// username requested is available for use. This includes verifying that an
    2663             :   /// application service has not claimed the username and that the username
    2664             :   /// fits the server's desired requirements (for example, a server could dictate
    2665             :   /// that it does not permit usernames with underscores).
    2666             :   ///
    2667             :   /// Matrix clients may wish to use this API prior to attempting registration,
    2668             :   /// however the clients must also be aware that using this API does not normally
    2669             :   /// reserve the username. This can mean that the username becomes unavailable
    2670             :   /// between checking its availability and attempting to register it.
    2671             :   ///
    2672             :   /// [username] The username to check the availability of.
    2673             :   ///
    2674             :   /// returns `available`:
    2675             :   /// A flag to indicate that the username is available. This should always
    2676             :   /// be `true` when the server replies with 200 OK.
    2677           1 :   Future<bool?> checkUsernameAvailability(String username) async {
    2678             :     final requestUri =
    2679           2 :         Uri(path: '_matrix/client/v3/register/available', queryParameters: {
    2680             :       'username': username,
    2681             :     });
    2682           3 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2683           2 :     final response = await httpClient.send(request);
    2684           2 :     final responseBody = await response.stream.toBytes();
    2685           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2686           1 :     final responseString = utf8.decode(responseBody);
    2687           1 :     final json = jsonDecode(responseString);
    2688           3 :     return ((v) => v != null ? v as bool : null)(json['available']);
    2689             :   }
    2690             : 
    2691             :   /// The homeserver must check that the given email address is **not**
    2692             :   /// already associated with an account on this homeserver. The homeserver
    2693             :   /// should validate the email itself, either by sending a validation email
    2694             :   /// itself or by using a service it has control over.
    2695             :   ///
    2696             :   /// [clientSecret] A unique string generated by the client, and used to identify the
    2697             :   /// validation attempt. It must be a string consisting of the characters
    2698             :   /// `[0-9a-zA-Z.=_-]`. Its length must not exceed 255 characters and it
    2699             :   /// must not be empty.
    2700             :   ///
    2701             :   ///
    2702             :   /// [email] The email address to validate.
    2703             :   ///
    2704             :   /// [nextLink] Optional. When the validation is completed, the identity server will
    2705             :   /// redirect the user to this URL. This option is ignored when submitting
    2706             :   /// 3PID validation information through a POST request.
    2707             :   ///
    2708             :   /// [sendAttempt] The server will only send an email if the `send_attempt`
    2709             :   /// is a number greater than the most recent one which it has seen,
    2710             :   /// scoped to that `email` + `client_secret` pair. This is to
    2711             :   /// avoid repeatedly sending the same email in the case of request
    2712             :   /// retries between the POSTing user and the identity server.
    2713             :   /// The client should increment this value if they desire a new
    2714             :   /// email (e.g. a reminder) to be sent. If they do not, the server
    2715             :   /// should respond with success but not resend the email.
    2716             :   ///
    2717             :   /// [idAccessToken] An access token previously registered with the identity server. Servers
    2718             :   /// can treat this as optional to distinguish between r0.5-compatible clients
    2719             :   /// and this specification version.
    2720             :   ///
    2721             :   /// Required if an `id_server` is supplied.
    2722             :   ///
    2723             :   /// [idServer] The hostname of the identity server to communicate with. May optionally
    2724             :   /// include a port. This parameter is ignored when the homeserver handles
    2725             :   /// 3PID verification.
    2726             :   ///
    2727             :   /// This parameter is deprecated with a plan to be removed in a future specification
    2728             :   /// version for `/account/password` and `/register` requests.
    2729           0 :   Future<RequestTokenResponse> requestTokenToRegisterEmail(
    2730             :       String clientSecret, String email, int sendAttempt,
    2731             :       {String? nextLink, String? idAccessToken, String? idServer}) async {
    2732             :     final requestUri =
    2733           0 :         Uri(path: '_matrix/client/v3/register/email/requestToken');
    2734           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    2735           0 :     request.headers['content-type'] = 'application/json';
    2736           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    2737           0 :       'client_secret': clientSecret,
    2738           0 :       'email': email,
    2739           0 :       if (nextLink != null) 'next_link': nextLink,
    2740           0 :       'send_attempt': sendAttempt,
    2741           0 :       if (idAccessToken != null) 'id_access_token': idAccessToken,
    2742           0 :       if (idServer != null) 'id_server': idServer,
    2743             :     }));
    2744           0 :     final response = await httpClient.send(request);
    2745           0 :     final responseBody = await response.stream.toBytes();
    2746           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2747           0 :     final responseString = utf8.decode(responseBody);
    2748           0 :     final json = jsonDecode(responseString);
    2749           0 :     return RequestTokenResponse.fromJson(json as Map<String, Object?>);
    2750             :   }
    2751             : 
    2752             :   /// The homeserver must check that the given phone number is **not**
    2753             :   /// already associated with an account on this homeserver. The homeserver
    2754             :   /// should validate the phone number itself, either by sending a validation
    2755             :   /// message itself or by using a service it has control over.
    2756             :   ///
    2757             :   /// [clientSecret] A unique string generated by the client, and used to identify the
    2758             :   /// validation attempt. It must be a string consisting of the characters
    2759             :   /// `[0-9a-zA-Z.=_-]`. Its length must not exceed 255 characters and it
    2760             :   /// must not be empty.
    2761             :   ///
    2762             :   ///
    2763             :   /// [country] The two-letter uppercase ISO-3166-1 alpha-2 country code that the
    2764             :   /// number in `phone_number` should be parsed as if it were dialled from.
    2765             :   ///
    2766             :   /// [nextLink] Optional. When the validation is completed, the identity server will
    2767             :   /// redirect the user to this URL. This option is ignored when submitting
    2768             :   /// 3PID validation information through a POST request.
    2769             :   ///
    2770             :   /// [phoneNumber] The phone number to validate.
    2771             :   ///
    2772             :   /// [sendAttempt] The server will only send an SMS if the `send_attempt` is a
    2773             :   /// number greater than the most recent one which it has seen,
    2774             :   /// scoped to that `country` + `phone_number` + `client_secret`
    2775             :   /// triple. This is to avoid repeatedly sending the same SMS in
    2776             :   /// the case of request retries between the POSTing user and the
    2777             :   /// identity server. The client should increment this value if
    2778             :   /// they desire a new SMS (e.g. a reminder) to be sent.
    2779             :   ///
    2780             :   /// [idAccessToken] An access token previously registered with the identity server. Servers
    2781             :   /// can treat this as optional to distinguish between r0.5-compatible clients
    2782             :   /// and this specification version.
    2783             :   ///
    2784             :   /// Required if an `id_server` is supplied.
    2785             :   ///
    2786             :   /// [idServer] The hostname of the identity server to communicate with. May optionally
    2787             :   /// include a port. This parameter is ignored when the homeserver handles
    2788             :   /// 3PID verification.
    2789             :   ///
    2790             :   /// This parameter is deprecated with a plan to be removed in a future specification
    2791             :   /// version for `/account/password` and `/register` requests.
    2792           0 :   Future<RequestTokenResponse> requestTokenToRegisterMSISDN(
    2793             :       String clientSecret, String country, String phoneNumber, int sendAttempt,
    2794             :       {String? nextLink, String? idAccessToken, String? idServer}) async {
    2795             :     final requestUri =
    2796           0 :         Uri(path: '_matrix/client/v3/register/msisdn/requestToken');
    2797           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    2798           0 :     request.headers['content-type'] = 'application/json';
    2799           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    2800           0 :       'client_secret': clientSecret,
    2801           0 :       'country': country,
    2802           0 :       if (nextLink != null) 'next_link': nextLink,
    2803           0 :       'phone_number': phoneNumber,
    2804           0 :       'send_attempt': sendAttempt,
    2805           0 :       if (idAccessToken != null) 'id_access_token': idAccessToken,
    2806           0 :       if (idServer != null) 'id_server': idServer,
    2807             :     }));
    2808           0 :     final response = await httpClient.send(request);
    2809           0 :     final responseBody = await response.stream.toBytes();
    2810           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2811           0 :     final responseString = utf8.decode(responseBody);
    2812           0 :     final json = jsonDecode(responseString);
    2813           0 :     return RequestTokenResponse.fromJson(json as Map<String, Object?>);
    2814             :   }
    2815             : 
    2816             :   /// Delete the keys from the backup.
    2817             :   ///
    2818             :   /// [version] The backup from which to delete the key
    2819           0 :   Future<RoomKeysUpdateResponse> deleteRoomKeys(String version) async {
    2820             :     final requestUri =
    2821           0 :         Uri(path: '_matrix/client/v3/room_keys/keys', queryParameters: {
    2822             :       'version': version,
    2823             :     });
    2824           0 :     final request = Request('DELETE', baseUri!.resolveUri(requestUri));
    2825           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2826           0 :     final response = await httpClient.send(request);
    2827           0 :     final responseBody = await response.stream.toBytes();
    2828           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2829           0 :     final responseString = utf8.decode(responseBody);
    2830           0 :     final json = jsonDecode(responseString);
    2831           0 :     return RoomKeysUpdateResponse.fromJson(json as Map<String, Object?>);
    2832             :   }
    2833             : 
    2834             :   /// Retrieve the keys from the backup.
    2835             :   ///
    2836             :   /// [version] The backup from which to retrieve the keys.
    2837           1 :   Future<RoomKeys> getRoomKeys(String version) async {
    2838             :     final requestUri =
    2839           2 :         Uri(path: '_matrix/client/v3/room_keys/keys', queryParameters: {
    2840             :       'version': version,
    2841             :     });
    2842           3 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2843           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2844           2 :     final response = await httpClient.send(request);
    2845           2 :     final responseBody = await response.stream.toBytes();
    2846           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2847           1 :     final responseString = utf8.decode(responseBody);
    2848           1 :     final json = jsonDecode(responseString);
    2849           1 :     return RoomKeys.fromJson(json as Map<String, Object?>);
    2850             :   }
    2851             : 
    2852             :   /// Store several keys in the backup.
    2853             :   ///
    2854             :   /// [version] The backup in which to store the keys. Must be the current backup.
    2855             :   ///
    2856             :   /// [backupData] The backup data.
    2857           4 :   Future<RoomKeysUpdateResponse> putRoomKeys(
    2858             :       String version, RoomKeys backupData) async {
    2859             :     final requestUri =
    2860           8 :         Uri(path: '_matrix/client/v3/room_keys/keys', queryParameters: {
    2861             :       'version': version,
    2862             :     });
    2863          12 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    2864          16 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2865           8 :     request.headers['content-type'] = 'application/json';
    2866          16 :     request.bodyBytes = utf8.encode(jsonEncode(backupData.toJson()));
    2867           8 :     final response = await httpClient.send(request);
    2868           8 :     final responseBody = await response.stream.toBytes();
    2869           8 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2870           4 :     final responseString = utf8.decode(responseBody);
    2871           4 :     final json = jsonDecode(responseString);
    2872           4 :     return RoomKeysUpdateResponse.fromJson(json as Map<String, Object?>);
    2873             :   }
    2874             : 
    2875             :   /// Delete the keys from the backup for a given room.
    2876             :   ///
    2877             :   /// [roomId] The ID of the room that the specified key is for.
    2878             :   ///
    2879             :   /// [version] The backup from which to delete the key.
    2880           0 :   Future<RoomKeysUpdateResponse> deleteRoomKeysByRoomId(
    2881             :       String roomId, String version) async {
    2882           0 :     final requestUri = Uri(
    2883           0 :         path: '_matrix/client/v3/room_keys/keys/${Uri.encodeComponent(roomId)}',
    2884           0 :         queryParameters: {
    2885             :           'version': version,
    2886             :         });
    2887           0 :     final request = Request('DELETE', baseUri!.resolveUri(requestUri));
    2888           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2889           0 :     final response = await httpClient.send(request);
    2890           0 :     final responseBody = await response.stream.toBytes();
    2891           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2892           0 :     final responseString = utf8.decode(responseBody);
    2893           0 :     final json = jsonDecode(responseString);
    2894           0 :     return RoomKeysUpdateResponse.fromJson(json as Map<String, Object?>);
    2895             :   }
    2896             : 
    2897             :   /// Retrieve the keys from the backup for a given room.
    2898             :   ///
    2899             :   /// [roomId] The ID of the room that the requested key is for.
    2900             :   ///
    2901             :   /// [version] The backup from which to retrieve the key.
    2902           1 :   Future<RoomKeyBackup> getRoomKeysByRoomId(
    2903             :       String roomId, String version) async {
    2904           1 :     final requestUri = Uri(
    2905           2 :         path: '_matrix/client/v3/room_keys/keys/${Uri.encodeComponent(roomId)}',
    2906           1 :         queryParameters: {
    2907             :           'version': version,
    2908             :         });
    2909           3 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2910           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2911           2 :     final response = await httpClient.send(request);
    2912           2 :     final responseBody = await response.stream.toBytes();
    2913           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2914           1 :     final responseString = utf8.decode(responseBody);
    2915           1 :     final json = jsonDecode(responseString);
    2916           1 :     return RoomKeyBackup.fromJson(json as Map<String, Object?>);
    2917             :   }
    2918             : 
    2919             :   /// Store several keys in the backup for a given room.
    2920             :   ///
    2921             :   /// [roomId] The ID of the room that the keys are for.
    2922             :   ///
    2923             :   /// [version] The backup in which to store the keys. Must be the current backup.
    2924             :   ///
    2925             :   /// [backupData] The backup data
    2926           0 :   Future<RoomKeysUpdateResponse> putRoomKeysByRoomId(
    2927             :       String roomId, String version, RoomKeyBackup backupData) async {
    2928           0 :     final requestUri = Uri(
    2929           0 :         path: '_matrix/client/v3/room_keys/keys/${Uri.encodeComponent(roomId)}',
    2930           0 :         queryParameters: {
    2931             :           'version': version,
    2932             :         });
    2933           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    2934           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2935           0 :     request.headers['content-type'] = 'application/json';
    2936           0 :     request.bodyBytes = utf8.encode(jsonEncode(backupData.toJson()));
    2937           0 :     final response = await httpClient.send(request);
    2938           0 :     final responseBody = await response.stream.toBytes();
    2939           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2940           0 :     final responseString = utf8.decode(responseBody);
    2941           0 :     final json = jsonDecode(responseString);
    2942           0 :     return RoomKeysUpdateResponse.fromJson(json as Map<String, Object?>);
    2943             :   }
    2944             : 
    2945             :   /// Delete a key from the backup.
    2946             :   ///
    2947             :   /// [roomId] The ID of the room that the specified key is for.
    2948             :   ///
    2949             :   /// [sessionId] The ID of the megolm session whose key is to be deleted.
    2950             :   ///
    2951             :   /// [version] The backup from which to delete the key
    2952           0 :   Future<RoomKeysUpdateResponse> deleteRoomKeyBySessionId(
    2953             :       String roomId, String sessionId, String version) async {
    2954           0 :     final requestUri = Uri(
    2955             :         path:
    2956           0 :             '_matrix/client/v3/room_keys/keys/${Uri.encodeComponent(roomId)}/${Uri.encodeComponent(sessionId)}',
    2957           0 :         queryParameters: {
    2958             :           'version': version,
    2959             :         });
    2960           0 :     final request = Request('DELETE', baseUri!.resolveUri(requestUri));
    2961           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2962           0 :     final response = await httpClient.send(request);
    2963           0 :     final responseBody = await response.stream.toBytes();
    2964           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2965           0 :     final responseString = utf8.decode(responseBody);
    2966           0 :     final json = jsonDecode(responseString);
    2967           0 :     return RoomKeysUpdateResponse.fromJson(json as Map<String, Object?>);
    2968             :   }
    2969             : 
    2970             :   /// Retrieve a key from the backup.
    2971             :   ///
    2972             :   /// [roomId] The ID of the room that the requested key is for.
    2973             :   ///
    2974             :   /// [sessionId] The ID of the megolm session whose key is requested.
    2975             :   ///
    2976             :   /// [version] The backup from which to retrieve the key.
    2977           1 :   Future<KeyBackupData> getRoomKeyBySessionId(
    2978             :       String roomId, String sessionId, String version) async {
    2979           1 :     final requestUri = Uri(
    2980             :         path:
    2981           3 :             '_matrix/client/v3/room_keys/keys/${Uri.encodeComponent(roomId)}/${Uri.encodeComponent(sessionId)}',
    2982           1 :         queryParameters: {
    2983             :           'version': version,
    2984             :         });
    2985           3 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    2986           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    2987           2 :     final response = await httpClient.send(request);
    2988           2 :     final responseBody = await response.stream.toBytes();
    2989           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    2990           1 :     final responseString = utf8.decode(responseBody);
    2991           1 :     final json = jsonDecode(responseString);
    2992           1 :     return KeyBackupData.fromJson(json as Map<String, Object?>);
    2993             :   }
    2994             : 
    2995             :   /// Store a key in the backup.
    2996             :   ///
    2997             :   /// [roomId] The ID of the room that the key is for.
    2998             :   ///
    2999             :   /// [sessionId] The ID of the megolm session that the key is for.
    3000             :   ///
    3001             :   /// [version] The backup in which to store the key. Must be the current backup.
    3002             :   ///
    3003             :   /// [data] The key data.
    3004           0 :   Future<RoomKeysUpdateResponse> putRoomKeyBySessionId(String roomId,
    3005             :       String sessionId, String version, KeyBackupData data) async {
    3006           0 :     final requestUri = Uri(
    3007             :         path:
    3008           0 :             '_matrix/client/v3/room_keys/keys/${Uri.encodeComponent(roomId)}/${Uri.encodeComponent(sessionId)}',
    3009           0 :         queryParameters: {
    3010             :           'version': version,
    3011             :         });
    3012           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    3013           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3014           0 :     request.headers['content-type'] = 'application/json';
    3015           0 :     request.bodyBytes = utf8.encode(jsonEncode(data.toJson()));
    3016           0 :     final response = await httpClient.send(request);
    3017           0 :     final responseBody = await response.stream.toBytes();
    3018           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3019           0 :     final responseString = utf8.decode(responseBody);
    3020           0 :     final json = jsonDecode(responseString);
    3021           0 :     return RoomKeysUpdateResponse.fromJson(json as Map<String, Object?>);
    3022             :   }
    3023             : 
    3024             :   /// Get information about the latest backup version.
    3025           5 :   Future<GetRoomKeysVersionCurrentResponse> getRoomKeysVersionCurrent() async {
    3026           5 :     final requestUri = Uri(path: '_matrix/client/v3/room_keys/version');
    3027          15 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3028          20 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3029          10 :     final response = await httpClient.send(request);
    3030          10 :     final responseBody = await response.stream.toBytes();
    3031          10 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3032           5 :     final responseString = utf8.decode(responseBody);
    3033           5 :     final json = jsonDecode(responseString);
    3034           5 :     return GetRoomKeysVersionCurrentResponse.fromJson(
    3035             :         json as Map<String, Object?>);
    3036             :   }
    3037             : 
    3038             :   /// Creates a new backup.
    3039             :   ///
    3040             :   /// [algorithm] The algorithm used for storing backups.
    3041             :   ///
    3042             :   /// [authData] Algorithm-dependent data. See the documentation for the backup
    3043             :   /// algorithms in [Server-side key backups](https://spec.matrix.org/unstable/client-server-api/#server-side-key-backups) for more information on the
    3044             :   /// expected format of the data.
    3045             :   ///
    3046             :   /// returns `version`:
    3047             :   /// The backup version. This is an opaque string.
    3048           1 :   Future<String> postRoomKeysVersion(
    3049             :       BackupAlgorithm algorithm, Map<String, Object?> authData) async {
    3050           1 :     final requestUri = Uri(path: '_matrix/client/v3/room_keys/version');
    3051           3 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3052           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3053           2 :     request.headers['content-type'] = 'application/json';
    3054           4 :     request.bodyBytes = utf8.encode(jsonEncode({
    3055           1 :       'algorithm': algorithm.name,
    3056             :       'auth_data': authData,
    3057             :     }));
    3058           2 :     final response = await httpClient.send(request);
    3059           2 :     final responseBody = await response.stream.toBytes();
    3060           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3061           1 :     final responseString = utf8.decode(responseBody);
    3062           1 :     final json = jsonDecode(responseString);
    3063           1 :     return json['version'] as String;
    3064             :   }
    3065             : 
    3066             :   /// Delete an existing key backup. Both the information about the backup,
    3067             :   /// as well as all key data related to the backup will be deleted.
    3068             :   ///
    3069             :   /// [version] The backup version to delete, as returned in the `version`
    3070             :   /// parameter in the response of
    3071             :   /// [`POST /_matrix/client/v3/room_keys/version`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv3room_keysversion)
    3072             :   /// or [`GET /_matrix/client/v3/room_keys/version/{version}`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3room_keysversionversion).
    3073           0 :   Future<void> deleteRoomKeysVersion(String version) async {
    3074           0 :     final requestUri = Uri(
    3075             :         path:
    3076           0 :             '_matrix/client/v3/room_keys/version/${Uri.encodeComponent(version)}');
    3077           0 :     final request = Request('DELETE', baseUri!.resolveUri(requestUri));
    3078           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3079           0 :     final response = await httpClient.send(request);
    3080           0 :     final responseBody = await response.stream.toBytes();
    3081           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3082           0 :     final responseString = utf8.decode(responseBody);
    3083           0 :     final json = jsonDecode(responseString);
    3084           0 :     return ignore(json);
    3085             :   }
    3086             : 
    3087             :   /// Get information about an existing backup.
    3088             :   ///
    3089             :   /// [version] The backup version to get, as returned in the `version` parameter
    3090             :   /// of the response in
    3091             :   /// [`POST /_matrix/client/v3/room_keys/version`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv3room_keysversion)
    3092             :   /// or this endpoint.
    3093           0 :   Future<GetRoomKeysVersionResponse> getRoomKeysVersion(String version) async {
    3094           0 :     final requestUri = Uri(
    3095             :         path:
    3096           0 :             '_matrix/client/v3/room_keys/version/${Uri.encodeComponent(version)}');
    3097           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3098           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3099           0 :     final response = await httpClient.send(request);
    3100           0 :     final responseBody = await response.stream.toBytes();
    3101           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3102           0 :     final responseString = utf8.decode(responseBody);
    3103           0 :     final json = jsonDecode(responseString);
    3104           0 :     return GetRoomKeysVersionResponse.fromJson(json as Map<String, Object?>);
    3105             :   }
    3106             : 
    3107             :   /// Update information about an existing backup.  Only `auth_data` can be modified.
    3108             :   ///
    3109             :   /// [version] The backup version to update, as returned in the `version`
    3110             :   /// parameter in the response of
    3111             :   /// [`POST /_matrix/client/v3/room_keys/version`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv3room_keysversion)
    3112             :   /// or [`GET /_matrix/client/v3/room_keys/version/{version}`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3room_keysversionversion).
    3113             :   ///
    3114             :   /// [algorithm] The algorithm used for storing backups.  Must be the same as
    3115             :   /// the algorithm currently used by the backup.
    3116             :   ///
    3117             :   /// [authData] Algorithm-dependent data. See the documentation for the backup
    3118             :   /// algorithms in [Server-side key backups](https://spec.matrix.org/unstable/client-server-api/#server-side-key-backups) for more information on the
    3119             :   /// expected format of the data.
    3120           0 :   Future<Map<String, Object?>> putRoomKeysVersion(String version,
    3121             :       BackupAlgorithm algorithm, Map<String, Object?> authData) async {
    3122           0 :     final requestUri = Uri(
    3123             :         path:
    3124           0 :             '_matrix/client/v3/room_keys/version/${Uri.encodeComponent(version)}');
    3125           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    3126           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3127           0 :     request.headers['content-type'] = 'application/json';
    3128           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    3129           0 :       'algorithm': algorithm.name,
    3130             :       'auth_data': authData,
    3131             :     }));
    3132           0 :     final response = await httpClient.send(request);
    3133           0 :     final responseBody = await response.stream.toBytes();
    3134           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3135           0 :     final responseString = utf8.decode(responseBody);
    3136           0 :     final json = jsonDecode(responseString);
    3137             :     return json as Map<String, Object?>;
    3138             :   }
    3139             : 
    3140             :   /// Get a list of aliases maintained by the local server for the
    3141             :   /// given room.
    3142             :   ///
    3143             :   /// This endpoint can be called by users who are in the room (external
    3144             :   /// users receive an `M_FORBIDDEN` error response). If the room's
    3145             :   /// `m.room.history_visibility` maps to `world_readable`, any
    3146             :   /// user can call this endpoint.
    3147             :   ///
    3148             :   /// Servers may choose to implement additional access control checks here,
    3149             :   /// such as allowing server administrators to view aliases regardless of
    3150             :   /// membership.
    3151             :   ///
    3152             :   /// **Note:**
    3153             :   /// Clients are recommended not to display this list of aliases prominently
    3154             :   /// as they are not curated, unlike those listed in the `m.room.canonical_alias`
    3155             :   /// state event.
    3156             :   ///
    3157             :   /// [roomId] The room ID to find local aliases of.
    3158             :   ///
    3159             :   /// returns `aliases`:
    3160             :   /// The server's local aliases on the room. Can be empty.
    3161           0 :   Future<List<String>> getLocalAliases(String roomId) async {
    3162           0 :     final requestUri = Uri(
    3163           0 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/aliases');
    3164           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3165           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3166           0 :     final response = await httpClient.send(request);
    3167           0 :     final responseBody = await response.stream.toBytes();
    3168           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3169           0 :     final responseString = utf8.decode(responseBody);
    3170           0 :     final json = jsonDecode(responseString);
    3171           0 :     return (json['aliases'] as List).map((v) => v as String).toList();
    3172             :   }
    3173             : 
    3174             :   /// Ban a user in the room. If the user is currently in the room, also kick them.
    3175             :   ///
    3176             :   /// When a user is banned from a room, they may not join it or be invited to it until they are unbanned.
    3177             :   ///
    3178             :   /// The caller must have the required power level in order to perform this operation.
    3179             :   ///
    3180             :   /// [roomId] The room identifier (not alias) from which the user should be banned.
    3181             :   ///
    3182             :   /// [reason] The reason the user has been banned. This will be supplied as the `reason` on the target's updated [`m.room.member`](https://spec.matrix.org/unstable/client-server-api/#mroommember) event.
    3183             :   ///
    3184             :   /// [userId] The fully qualified user ID of the user being banned.
    3185           5 :   Future<void> ban(String roomId, String userId, {String? reason}) async {
    3186             :     final requestUri =
    3187          15 :         Uri(path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/ban');
    3188          15 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3189          20 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3190          10 :     request.headers['content-type'] = 'application/json';
    3191          20 :     request.bodyBytes = utf8.encode(jsonEncode({
    3192           0 :       if (reason != null) 'reason': reason,
    3193           5 :       'user_id': userId,
    3194             :     }));
    3195          10 :     final response = await httpClient.send(request);
    3196          10 :     final responseBody = await response.stream.toBytes();
    3197          10 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3198           5 :     final responseString = utf8.decode(responseBody);
    3199           5 :     final json = jsonDecode(responseString);
    3200           5 :     return ignore(json);
    3201             :   }
    3202             : 
    3203             :   /// This API returns a number of events that happened just before and
    3204             :   /// after the specified event. This allows clients to get the context
    3205             :   /// surrounding an event.
    3206             :   ///
    3207             :   /// *Note*: This endpoint supports lazy-loading of room member events. See
    3208             :   /// [Lazy-loading room members](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) for more information.
    3209             :   ///
    3210             :   /// [roomId] The room to get events from.
    3211             :   ///
    3212             :   /// [eventId] The event to get context around.
    3213             :   ///
    3214             :   /// [limit] The maximum number of context events to return. The limit applies
    3215             :   /// to the sum of the `events_before` and `events_after` arrays. The
    3216             :   /// requested event ID is always returned in `event` even if `limit` is
    3217             :   /// 0. Defaults to 10.
    3218             :   ///
    3219             :   /// [filter] A JSON `RoomEventFilter` to filter the returned events with. The
    3220             :   /// filter is only applied to `events_before`, `events_after`, and
    3221             :   /// `state`. It is not applied to the `event` itself. The filter may
    3222             :   /// be applied before or/and after the `limit` parameter - whichever the
    3223             :   /// homeserver prefers.
    3224             :   ///
    3225             :   /// See [Filtering](https://spec.matrix.org/unstable/client-server-api/#filtering) for more information.
    3226           0 :   Future<EventContext> getEventContext(String roomId, String eventId,
    3227             :       {int? limit, String? filter}) async {
    3228           0 :     final requestUri = Uri(
    3229             :         path:
    3230           0 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/context/${Uri.encodeComponent(eventId)}',
    3231           0 :         queryParameters: {
    3232           0 :           if (limit != null) 'limit': limit.toString(),
    3233           0 :           if (filter != null) 'filter': filter,
    3234             :         });
    3235           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3236           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3237           0 :     final response = await httpClient.send(request);
    3238           0 :     final responseBody = await response.stream.toBytes();
    3239           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3240           0 :     final responseString = utf8.decode(responseBody);
    3241           0 :     final json = jsonDecode(responseString);
    3242           0 :     return EventContext.fromJson(json as Map<String, Object?>);
    3243             :   }
    3244             : 
    3245             :   /// Get a single event based on `roomId/eventId`. You must have permission to
    3246             :   /// retrieve this event e.g. by being a member in the room for this event.
    3247             :   ///
    3248             :   /// [roomId] The ID of the room the event is in.
    3249             :   ///
    3250             :   /// [eventId] The event ID to get.
    3251           5 :   Future<MatrixEvent> getOneRoomEvent(String roomId, String eventId) async {
    3252           5 :     final requestUri = Uri(
    3253             :         path:
    3254          15 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/event/${Uri.encodeComponent(eventId)}');
    3255          15 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3256          20 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3257          10 :     final response = await httpClient.send(request);
    3258          10 :     final responseBody = await response.stream.toBytes();
    3259          12 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3260           5 :     final responseString = utf8.decode(responseBody);
    3261           5 :     final json = jsonDecode(responseString);
    3262           5 :     return MatrixEvent.fromJson(json as Map<String, Object?>);
    3263             :   }
    3264             : 
    3265             :   /// This API stops a user remembering about a particular room.
    3266             :   ///
    3267             :   /// In general, history is a first class citizen in Matrix. After this API
    3268             :   /// is called, however, a user will no longer be able to retrieve history
    3269             :   /// for this room. If all users on a homeserver forget a room, the room is
    3270             :   /// eligible for deletion from that homeserver.
    3271             :   ///
    3272             :   /// If the user is currently joined to the room, they must leave the room
    3273             :   /// before calling this API.
    3274             :   ///
    3275             :   /// [roomId] The room identifier to forget.
    3276           0 :   Future<void> forgetRoom(String roomId) async {
    3277           0 :     final requestUri = Uri(
    3278           0 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/forget');
    3279           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3280           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3281           0 :     final response = await httpClient.send(request);
    3282           0 :     final responseBody = await response.stream.toBytes();
    3283           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3284           0 :     final responseString = utf8.decode(responseBody);
    3285           0 :     final json = jsonDecode(responseString);
    3286           0 :     return ignore(json);
    3287             :   }
    3288             : 
    3289             :   /// *Note that there are two forms of this API, which are documented separately.
    3290             :   /// This version of the API does not require that the inviter know the Matrix
    3291             :   /// identifier of the invitee, and instead relies on third party identifiers.
    3292             :   /// The homeserver uses an identity server to perform the mapping from
    3293             :   /// third party identifier to a Matrix identifier. The other is documented in the*
    3294             :   /// [joining rooms section](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv3roomsroomidinvite).
    3295             :   ///
    3296             :   /// This API invites a user to participate in a particular room.
    3297             :   /// They do not start participating in the room until they actually join the
    3298             :   /// room.
    3299             :   ///
    3300             :   /// Only users currently in a particular room can invite other users to
    3301             :   /// join that room.
    3302             :   ///
    3303             :   /// If the identity server did know the Matrix user identifier for the
    3304             :   /// third party identifier, the homeserver will append a `m.room.member`
    3305             :   /// event to the room.
    3306             :   ///
    3307             :   /// If the identity server does not know a Matrix user identifier for the
    3308             :   /// passed third party identifier, the homeserver will issue an invitation
    3309             :   /// which can be accepted upon providing proof of ownership of the third
    3310             :   /// party identifier. This is achieved by the identity server generating a
    3311             :   /// token, which it gives to the inviting homeserver. The homeserver will
    3312             :   /// add an `m.room.third_party_invite` event into the graph for the room,
    3313             :   /// containing that token.
    3314             :   ///
    3315             :   /// When the invitee binds the invited third party identifier to a Matrix
    3316             :   /// user ID, the identity server will give the user a list of pending
    3317             :   /// invitations, each containing:
    3318             :   ///
    3319             :   /// - The room ID to which they were invited
    3320             :   ///
    3321             :   /// - The token given to the homeserver
    3322             :   ///
    3323             :   /// - A signature of the token, signed with the identity server's private key
    3324             :   ///
    3325             :   /// - The matrix user ID who invited them to the room
    3326             :   ///
    3327             :   /// If a token is requested from the identity server, the homeserver will
    3328             :   /// append a `m.room.third_party_invite` event to the room.
    3329             :   ///
    3330             :   /// [roomId] The room identifier (not alias) to which to invite the user.
    3331             :   ///
    3332             :   /// [address] The invitee's third party identifier.
    3333             :   ///
    3334             :   /// [idAccessToken] An access token previously registered with the identity server. Servers
    3335             :   /// can treat this as optional to distinguish between r0.5-compatible clients
    3336             :   /// and this specification version.
    3337             :   ///
    3338             :   /// [idServer] The hostname+port of the identity server which should be used for third party identifier lookups.
    3339             :   ///
    3340             :   /// [medium] The kind of address being passed in the address field, for example
    3341             :   /// `email` (see [the list of recognised values](https://spec.matrix.org/unstable/appendices/#3pid-types)).
    3342           0 :   Future<void> inviteBy3PID(String roomId, String address, String idAccessToken,
    3343             :       String idServer, String medium) async {
    3344           0 :     final requestUri = Uri(
    3345           0 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/invite');
    3346           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3347           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3348           0 :     request.headers['content-type'] = 'application/json';
    3349           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    3350             :       'address': address,
    3351             :       'id_access_token': idAccessToken,
    3352             :       'id_server': idServer,
    3353             :       'medium': medium,
    3354             :     }));
    3355           0 :     final response = await httpClient.send(request);
    3356           0 :     final responseBody = await response.stream.toBytes();
    3357           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3358           0 :     final responseString = utf8.decode(responseBody);
    3359           0 :     final json = jsonDecode(responseString);
    3360           0 :     return ignore(json);
    3361             :   }
    3362             : 
    3363             :   /// *Note that there are two forms of this API, which are documented separately.
    3364             :   /// This version of the API requires that the inviter knows the Matrix
    3365             :   /// identifier of the invitee. The other is documented in the
    3366             :   /// [third party invites](https://spec.matrix.org/unstable/client-server-api/#third-party-invites) section.*
    3367             :   ///
    3368             :   /// This API invites a user to participate in a particular room.
    3369             :   /// They do not start participating in the room until they actually join the
    3370             :   /// room.
    3371             :   ///
    3372             :   /// Only users currently in a particular room can invite other users to
    3373             :   /// join that room.
    3374             :   ///
    3375             :   /// If the user was invited to the room, the homeserver will append a
    3376             :   /// `m.room.member` event to the room.
    3377             :   ///
    3378             :   /// [roomId] The room identifier (not alias) to which to invite the user.
    3379             :   ///
    3380             :   /// [reason] Optional reason to be included as the `reason` on the subsequent
    3381             :   /// membership event.
    3382             :   ///
    3383             :   /// [userId] The fully qualified user ID of the invitee.
    3384           3 :   Future<void> inviteUser(String roomId, String userId,
    3385             :       {String? reason}) async {
    3386           3 :     final requestUri = Uri(
    3387           6 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/invite');
    3388           9 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3389          12 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3390           6 :     request.headers['content-type'] = 'application/json';
    3391          12 :     request.bodyBytes = utf8.encode(jsonEncode({
    3392           0 :       if (reason != null) 'reason': reason,
    3393           3 :       'user_id': userId,
    3394             :     }));
    3395           6 :     final response = await httpClient.send(request);
    3396           6 :     final responseBody = await response.stream.toBytes();
    3397           6 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3398           3 :     final responseString = utf8.decode(responseBody);
    3399           3 :     final json = jsonDecode(responseString);
    3400           3 :     return ignore(json);
    3401             :   }
    3402             : 
    3403             :   /// *Note that this API requires a room ID, not alias.*
    3404             :   /// `/join/{roomIdOrAlias}` *exists if you have a room alias.*
    3405             :   ///
    3406             :   /// This API starts a user participating in a particular room, if that user
    3407             :   /// is allowed to participate in that room. After this call, the client is
    3408             :   /// allowed to see all current state events in the room, and all subsequent
    3409             :   /// events associated with the room until the user leaves the room.
    3410             :   ///
    3411             :   /// After a user has joined a room, the room will appear as an entry in the
    3412             :   /// response of the [`/initialSync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3initialsync)
    3413             :   /// and [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync) APIs.
    3414             :   ///
    3415             :   /// [roomId] The room identifier (not alias) to join.
    3416             :   ///
    3417             :   /// [reason] Optional reason to be included as the `reason` on the subsequent
    3418             :   /// membership event.
    3419             :   ///
    3420             :   /// [thirdPartySigned] If supplied, the homeserver must verify that it matches a pending
    3421             :   /// `m.room.third_party_invite` event in the room, and perform
    3422             :   /// key validity checking if required by the event.
    3423             :   ///
    3424             :   /// returns `room_id`:
    3425             :   /// The joined room ID.
    3426           0 :   Future<String> joinRoomById(String roomId,
    3427             :       {String? reason, ThirdPartySigned? thirdPartySigned}) async {
    3428           0 :     final requestUri = Uri(
    3429           0 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/join');
    3430           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3431           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3432           0 :     request.headers['content-type'] = 'application/json';
    3433           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    3434           0 :       if (reason != null) 'reason': reason,
    3435             :       if (thirdPartySigned != null)
    3436           0 :         'third_party_signed': thirdPartySigned.toJson(),
    3437             :     }));
    3438           0 :     final response = await httpClient.send(request);
    3439           0 :     final responseBody = await response.stream.toBytes();
    3440           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3441           0 :     final responseString = utf8.decode(responseBody);
    3442           0 :     final json = jsonDecode(responseString);
    3443           0 :     return json['room_id'] as String;
    3444             :   }
    3445             : 
    3446             :   /// This API returns a map of MXIDs to member info objects for members of the room. The current user must be in the room for it to work, unless it is an Application Service in which case any of the AS's users must be in the room. This API is primarily for Application Services and should be faster to respond than `/members` as it can be implemented more efficiently on the server.
    3447             :   ///
    3448             :   /// [roomId] The room to get the members of.
    3449             :   ///
    3450             :   /// returns `joined`:
    3451             :   /// A map from user ID to a RoomMember object.
    3452           0 :   Future<Map<String, RoomMember>?> getJoinedMembersByRoom(String roomId) async {
    3453           0 :     final requestUri = Uri(
    3454             :         path:
    3455           0 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/joined_members');
    3456           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3457           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3458           0 :     final response = await httpClient.send(request);
    3459           0 :     final responseBody = await response.stream.toBytes();
    3460           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3461           0 :     final responseString = utf8.decode(responseBody);
    3462           0 :     final json = jsonDecode(responseString);
    3463           0 :     return ((v) => v != null
    3464           0 :         ? (v as Map<String, Object?>).map((k, v) =>
    3465           0 :             MapEntry(k, RoomMember.fromJson(v as Map<String, Object?>)))
    3466           0 :         : null)(json['joined']);
    3467             :   }
    3468             : 
    3469             :   /// Kick a user from the room.
    3470             :   ///
    3471             :   /// The caller must have the required power level in order to perform this operation.
    3472             :   ///
    3473             :   /// Kicking a user adjusts the target member's membership state to be `leave` with an
    3474             :   /// optional `reason`. Like with other membership changes, a user can directly adjust
    3475             :   /// the target member's state by making a request to `/rooms/<room id>/state/m.room.member/<user id>`.
    3476             :   ///
    3477             :   /// [roomId] The room identifier (not alias) from which the user should be kicked.
    3478             :   ///
    3479             :   /// [reason] The reason the user has been kicked. This will be supplied as the
    3480             :   /// `reason` on the target's updated [`m.room.member`](https://spec.matrix.org/unstable/client-server-api/#mroommember) event.
    3481             :   ///
    3482             :   /// [userId] The fully qualified user ID of the user being kicked.
    3483           5 :   Future<void> kick(String roomId, String userId, {String? reason}) async {
    3484           5 :     final requestUri = Uri(
    3485          10 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/kick');
    3486          15 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3487          20 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3488          10 :     request.headers['content-type'] = 'application/json';
    3489          20 :     request.bodyBytes = utf8.encode(jsonEncode({
    3490           0 :       if (reason != null) 'reason': reason,
    3491           5 :       'user_id': userId,
    3492             :     }));
    3493          10 :     final response = await httpClient.send(request);
    3494          10 :     final responseBody = await response.stream.toBytes();
    3495          10 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3496           5 :     final responseString = utf8.decode(responseBody);
    3497           5 :     final json = jsonDecode(responseString);
    3498           5 :     return ignore(json);
    3499             :   }
    3500             : 
    3501             :   /// This API stops a user participating in a particular room.
    3502             :   ///
    3503             :   /// If the user was already in the room, they will no longer be able to see
    3504             :   /// new events in the room. If the room requires an invite to join, they
    3505             :   /// will need to be re-invited before they can re-join.
    3506             :   ///
    3507             :   /// If the user was invited to the room, but had not joined, this call
    3508             :   /// serves to reject the invite.
    3509             :   ///
    3510             :   /// The user will still be allowed to retrieve history from the room which
    3511             :   /// they were previously allowed to see.
    3512             :   ///
    3513             :   /// [roomId] The room identifier to leave.
    3514             :   ///
    3515             :   /// [reason] Optional reason to be included as the `reason` on the subsequent
    3516             :   /// membership event.
    3517           1 :   Future<void> leaveRoom(String roomId, {String? reason}) async {
    3518           1 :     final requestUri = Uri(
    3519           2 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/leave');
    3520           3 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3521           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3522           2 :     request.headers['content-type'] = 'application/json';
    3523           4 :     request.bodyBytes = utf8.encode(jsonEncode({
    3524           0 :       if (reason != null) 'reason': reason,
    3525             :     }));
    3526           2 :     final response = await httpClient.send(request);
    3527           2 :     final responseBody = await response.stream.toBytes();
    3528           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3529           1 :     final responseString = utf8.decode(responseBody);
    3530           1 :     final json = jsonDecode(responseString);
    3531           1 :     return ignore(json);
    3532             :   }
    3533             : 
    3534             :   /// Get the list of members for this room.
    3535             :   ///
    3536             :   /// [roomId] The room to get the member events for.
    3537             :   ///
    3538             :   /// [at] The point in time (pagination token) to return members for in the room.
    3539             :   /// This token can be obtained from a `prev_batch` token returned for
    3540             :   /// each room by the sync API. Defaults to the current state of the room,
    3541             :   /// as determined by the server.
    3542             :   ///
    3543             :   /// [membership] The kind of membership to filter for. Defaults to no filtering if
    3544             :   /// unspecified. When specified alongside `not_membership`, the two
    3545             :   /// parameters create an 'or' condition: either the membership *is*
    3546             :   /// the same as `membership` **or** *is not* the same as `not_membership`.
    3547             :   ///
    3548             :   /// [notMembership] The kind of membership to exclude from the results. Defaults to no
    3549             :   /// filtering if unspecified.
    3550             :   ///
    3551             :   /// returns `chunk`:
    3552             :   ///
    3553           1 :   Future<List<MatrixEvent>?> getMembersByRoom(String roomId,
    3554             :       {String? at, Membership? membership, Membership? notMembership}) async {
    3555           1 :     final requestUri = Uri(
    3556           2 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/members',
    3557           1 :         queryParameters: {
    3558           0 :           if (at != null) 'at': at,
    3559           0 :           if (membership != null) 'membership': membership.name,
    3560           0 :           if (notMembership != null) 'not_membership': notMembership.name,
    3561             :         });
    3562           3 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3563           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3564           2 :     final response = await httpClient.send(request);
    3565           2 :     final responseBody = await response.stream.toBytes();
    3566           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3567           1 :     final responseString = utf8.decode(responseBody);
    3568           1 :     final json = jsonDecode(responseString);
    3569           1 :     return ((v) => v != null
    3570             :         ? (v as List)
    3571           3 :             .map((v) => MatrixEvent.fromJson(v as Map<String, Object?>))
    3572           1 :             .toList()
    3573           2 :         : null)(json['chunk']);
    3574             :   }
    3575             : 
    3576             :   /// This API returns a list of message and state events for a room. It uses
    3577             :   /// pagination query parameters to paginate history in the room.
    3578             :   ///
    3579             :   /// *Note*: This endpoint supports lazy-loading of room member events. See
    3580             :   /// [Lazy-loading room members](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) for more information.
    3581             :   ///
    3582             :   /// [roomId] The room to get events from.
    3583             :   ///
    3584             :   /// [from] The token to start returning events from. This token can be obtained
    3585             :   /// from a `prev_batch` or `next_batch` token returned by the `/sync` endpoint,
    3586             :   /// or from an `end` token returned by a previous request to this endpoint.
    3587             :   ///
    3588             :   /// This endpoint can also accept a value returned as a `start` token
    3589             :   /// by a previous request to this endpoint, though servers are not
    3590             :   /// required to support this. Clients should not rely on the behaviour.
    3591             :   ///
    3592             :   /// If it is not provided, the homeserver shall return a list of messages
    3593             :   /// from the first or last (per the value of the `dir` parameter) visible
    3594             :   /// event in the room history for the requesting user.
    3595             :   ///
    3596             :   /// [to] The token to stop returning events at. This token can be obtained from
    3597             :   /// a `prev_batch` or `next_batch` token returned by the `/sync` endpoint,
    3598             :   /// or from an `end` token returned by a previous request to this endpoint.
    3599             :   ///
    3600             :   /// [dir] The direction to return events from. If this is set to `f`, events
    3601             :   /// will be returned in chronological order starting at `from`. If it
    3602             :   /// is set to `b`, events will be returned in *reverse* chronological
    3603             :   /// order, again starting at `from`.
    3604             :   ///
    3605             :   /// [limit] The maximum number of events to return. Default: 10.
    3606             :   ///
    3607             :   /// [filter] A JSON RoomEventFilter to filter returned events with.
    3608           4 :   Future<GetRoomEventsResponse> getRoomEvents(String roomId, Direction dir,
    3609             :       {String? from, String? to, int? limit, String? filter}) async {
    3610           4 :     final requestUri = Uri(
    3611           8 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/messages',
    3612           4 :         queryParameters: {
    3613           4 :           if (from != null) 'from': from,
    3614           0 :           if (to != null) 'to': to,
    3615           8 :           'dir': dir.name,
    3616           8 :           if (limit != null) 'limit': limit.toString(),
    3617           4 :           if (filter != null) 'filter': filter,
    3618             :         });
    3619          12 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3620          16 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3621           8 :     final response = await httpClient.send(request);
    3622           8 :     final responseBody = await response.stream.toBytes();
    3623           8 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3624           4 :     final responseString = utf8.decode(responseBody);
    3625           4 :     final json = jsonDecode(responseString);
    3626           4 :     return GetRoomEventsResponse.fromJson(json as Map<String, Object?>);
    3627             :   }
    3628             : 
    3629             :   /// Sets the position of the read marker for a given room, and optionally
    3630             :   /// the read receipt's location.
    3631             :   ///
    3632             :   /// [roomId] The room ID to set the read marker in for the user.
    3633             :   ///
    3634             :   /// [mFullyRead] The event ID the read marker should be located at. The
    3635             :   /// event MUST belong to the room.
    3636             :   ///
    3637             :   /// [mRead] The event ID to set the read receipt location at. This is
    3638             :   /// equivalent to calling `/receipt/m.read/$elsewhere:example.org`
    3639             :   /// and is provided here to save that extra call.
    3640             :   ///
    3641             :   /// [mReadPrivate] The event ID to set the *private* read receipt location at. This
    3642             :   /// equivalent to calling `/receipt/m.read.private/$elsewhere:example.org`
    3643             :   /// and is provided here to save that extra call.
    3644           4 :   Future<void> setReadMarker(String roomId,
    3645             :       {String? mFullyRead, String? mRead, String? mReadPrivate}) async {
    3646           4 :     final requestUri = Uri(
    3647             :         path:
    3648           8 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/read_markers');
    3649          12 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3650          16 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3651           8 :     request.headers['content-type'] = 'application/json';
    3652          16 :     request.bodyBytes = utf8.encode(jsonEncode({
    3653           4 :       if (mFullyRead != null) 'm.fully_read': mFullyRead,
    3654           2 :       if (mRead != null) 'm.read': mRead,
    3655           2 :       if (mReadPrivate != null) 'm.read.private': mReadPrivate,
    3656             :     }));
    3657           8 :     final response = await httpClient.send(request);
    3658           8 :     final responseBody = await response.stream.toBytes();
    3659           8 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3660           4 :     final responseString = utf8.decode(responseBody);
    3661           4 :     final json = jsonDecode(responseString);
    3662           4 :     return ignore(json);
    3663             :   }
    3664             : 
    3665             :   /// This API updates the marker for the given receipt type to the event ID
    3666             :   /// specified.
    3667             :   ///
    3668             :   /// [roomId] The room in which to send the event.
    3669             :   ///
    3670             :   /// [receiptType] The type of receipt to send. This can also be `m.fully_read` as an
    3671             :   /// alternative to [`/read_markers`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv3roomsroomidread_markers).
    3672             :   ///
    3673             :   /// Note that `m.fully_read` does not appear under `m.receipt`: this endpoint
    3674             :   /// effectively calls `/read_markers` internally when presented with a receipt
    3675             :   /// type of `m.fully_read`.
    3676             :   ///
    3677             :   /// [eventId] The event ID to acknowledge up to.
    3678             :   ///
    3679             :   /// [threadId] The root thread event's ID (or `main`) for which
    3680             :   /// thread this receipt is intended to be under. If
    3681             :   /// not specified, the read receipt is *unthreaded*
    3682             :   /// (default).
    3683           0 :   Future<void> postReceipt(
    3684             :       String roomId, ReceiptType receiptType, String eventId,
    3685             :       {String? threadId}) async {
    3686           0 :     final requestUri = Uri(
    3687             :         path:
    3688           0 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/receipt/${Uri.encodeComponent(receiptType.name)}/${Uri.encodeComponent(eventId)}');
    3689           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3690           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3691           0 :     request.headers['content-type'] = 'application/json';
    3692           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    3693           0 :       if (threadId != null) 'thread_id': threadId,
    3694             :     }));
    3695           0 :     final response = await httpClient.send(request);
    3696           0 :     final responseBody = await response.stream.toBytes();
    3697           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3698           0 :     final responseString = utf8.decode(responseBody);
    3699           0 :     final json = jsonDecode(responseString);
    3700           0 :     return ignore(json);
    3701             :   }
    3702             : 
    3703             :   /// Strips all information out of an event which isn't critical to the
    3704             :   /// integrity of the server-side representation of the room.
    3705             :   ///
    3706             :   /// This cannot be undone.
    3707             :   ///
    3708             :   /// Any user with a power level greater than or equal to the `m.room.redaction`
    3709             :   /// event power level may send redaction events in the room. If the user's power
    3710             :   /// level greater is also greater than or equal to the `redact` power level
    3711             :   /// of the room, the user may redact events sent by other users.
    3712             :   ///
    3713             :   /// Server administrators may redact events sent by users on their server.
    3714             :   ///
    3715             :   /// [roomId] The room from which to redact the event.
    3716             :   ///
    3717             :   /// [eventId] The ID of the event to redact
    3718             :   ///
    3719             :   /// [txnId] The [transaction ID](https://spec.matrix.org/unstable/client-server-api/#transaction-identifiers) for this event. Clients should generate a
    3720             :   /// unique ID; it will be used by the server to ensure idempotency of requests.
    3721             :   ///
    3722             :   /// [reason] The reason for the event being redacted.
    3723             :   ///
    3724             :   /// returns `event_id`:
    3725             :   /// A unique identifier for the event.
    3726           1 :   Future<String?> redactEvent(String roomId, String eventId, String txnId,
    3727             :       {String? reason}) async {
    3728           1 :     final requestUri = Uri(
    3729             :         path:
    3730           4 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/redact/${Uri.encodeComponent(eventId)}/${Uri.encodeComponent(txnId)}');
    3731           3 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    3732           4 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3733           2 :     request.headers['content-type'] = 'application/json';
    3734           4 :     request.bodyBytes = utf8.encode(jsonEncode({
    3735           1 :       if (reason != null) 'reason': reason,
    3736             :     }));
    3737           2 :     final response = await httpClient.send(request);
    3738           2 :     final responseBody = await response.stream.toBytes();
    3739           2 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3740           1 :     final responseString = utf8.decode(responseBody);
    3741           1 :     final json = jsonDecode(responseString);
    3742           3 :     return ((v) => v != null ? v as String : null)(json['event_id']);
    3743             :   }
    3744             : 
    3745             :   /// Reports an event as inappropriate to the server, which may then notify
    3746             :   /// the appropriate people.
    3747             :   ///
    3748             :   /// [roomId] The room in which the event being reported is located.
    3749             :   ///
    3750             :   /// [eventId] The event to report.
    3751             :   ///
    3752             :   /// [reason] The reason the content is being reported. May be blank.
    3753             :   ///
    3754             :   /// [score] The score to rate this content as where -100 is most offensive
    3755             :   /// and 0 is inoffensive.
    3756           0 :   Future<void> reportContent(String roomId, String eventId,
    3757             :       {String? reason, int? score}) async {
    3758           0 :     final requestUri = Uri(
    3759             :         path:
    3760           0 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/report/${Uri.encodeComponent(eventId)}');
    3761           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3762           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3763           0 :     request.headers['content-type'] = 'application/json';
    3764           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    3765           0 :       if (reason != null) 'reason': reason,
    3766           0 :       if (score != null) 'score': score,
    3767             :     }));
    3768           0 :     final response = await httpClient.send(request);
    3769           0 :     final responseBody = await response.stream.toBytes();
    3770           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3771           0 :     final responseString = utf8.decode(responseBody);
    3772           0 :     final json = jsonDecode(responseString);
    3773           0 :     return ignore(json);
    3774             :   }
    3775             : 
    3776             :   /// This endpoint is used to send a message event to a room. Message events
    3777             :   /// allow access to historical events and pagination, making them suited
    3778             :   /// for "once-off" activity in a room.
    3779             :   ///
    3780             :   /// The body of the request should be the content object of the event; the
    3781             :   /// fields in this object will vary depending on the type of event. See
    3782             :   /// [Room Events](https://spec.matrix.org/unstable/client-server-api/#room-events) for the m. event specification.
    3783             :   ///
    3784             :   /// [roomId] The room to send the event to.
    3785             :   ///
    3786             :   /// [eventType] The type of event to send.
    3787             :   ///
    3788             :   /// [txnId] The [transaction ID](https://spec.matrix.org/unstable/client-server-api/#transaction-identifiers) for this event. Clients should generate an
    3789             :   /// ID unique across requests with the same access token; it will be
    3790             :   /// used by the server to ensure idempotency of requests.
    3791             :   ///
    3792             :   /// [body]
    3793             :   ///
    3794             :   /// returns `event_id`:
    3795             :   /// A unique identifier for the event.
    3796          10 :   Future<String> sendMessage(String roomId, String eventType, String txnId,
    3797             :       Map<String, Object?> body) async {
    3798          10 :     final requestUri = Uri(
    3799             :         path:
    3800          40 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/send/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(txnId)}');
    3801          30 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    3802          40 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3803          20 :     request.headers['content-type'] = 'application/json';
    3804          30 :     request.bodyBytes = utf8.encode(jsonEncode(body));
    3805             :     const maxBodySize = 60000;
    3806          30 :     if (request.bodyBytes.length > maxBodySize) {
    3807           6 :       bodySizeExceeded(maxBodySize, request.bodyBytes.length);
    3808             :     }
    3809          20 :     final response = await httpClient.send(request);
    3810          20 :     final responseBody = await response.stream.toBytes();
    3811          22 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3812          10 :     final responseString = utf8.decode(responseBody);
    3813          10 :     final json = jsonDecode(responseString);
    3814          10 :     return json['event_id'] as String;
    3815             :   }
    3816             : 
    3817             :   /// Get the state events for the current state of a room.
    3818             :   ///
    3819             :   /// [roomId] The room to look up the state for.
    3820           0 :   Future<List<MatrixEvent>> getRoomState(String roomId) async {
    3821           0 :     final requestUri = Uri(
    3822           0 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/state');
    3823           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3824           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3825           0 :     final response = await httpClient.send(request);
    3826           0 :     final responseBody = await response.stream.toBytes();
    3827           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3828           0 :     final responseString = utf8.decode(responseBody);
    3829           0 :     final json = jsonDecode(responseString);
    3830             :     return (json as List)
    3831           0 :         .map((v) => MatrixEvent.fromJson(v as Map<String, Object?>))
    3832           0 :         .toList();
    3833             :   }
    3834             : 
    3835             :   /// Looks up the contents of a state event in a room. If the user is
    3836             :   /// joined to the room then the state is taken from the current
    3837             :   /// state of the room. If the user has left the room then the state is
    3838             :   /// taken from the state of the room when they left.
    3839             :   ///
    3840             :   /// [roomId] The room to look up the state in.
    3841             :   ///
    3842             :   /// [eventType] The type of state to look up.
    3843             :   ///
    3844             :   /// [stateKey] The key of the state to look up. Defaults to an empty string. When
    3845             :   /// an empty string, the trailing slash on this endpoint is optional.
    3846           7 :   Future<Map<String, Object?>> getRoomStateWithKey(
    3847             :       String roomId, String eventType, String stateKey) async {
    3848           7 :     final requestUri = Uri(
    3849             :         path:
    3850          28 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/state/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(stateKey)}');
    3851          19 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    3852          24 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3853          12 :     final response = await httpClient.send(request);
    3854          12 :     final responseBody = await response.stream.toBytes();
    3855          15 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3856           6 :     final responseString = utf8.decode(responseBody);
    3857           6 :     final json = jsonDecode(responseString);
    3858             :     return json as Map<String, Object?>;
    3859             :   }
    3860             : 
    3861             :   /// State events can be sent using this endpoint.  These events will be
    3862             :   /// overwritten if `<room id>`, `<event type>` and `<state key>` all
    3863             :   /// match.
    3864             :   ///
    3865             :   /// Requests to this endpoint **cannot use transaction IDs**
    3866             :   /// like other `PUT` paths because they cannot be differentiated from the
    3867             :   /// `state_key`. Furthermore, `POST` is unsupported on state paths.
    3868             :   ///
    3869             :   /// The body of the request should be the content object of the event; the
    3870             :   /// fields in this object will vary depending on the type of event. See
    3871             :   /// [Room Events](https://spec.matrix.org/unstable/client-server-api/#room-events) for the `m.` event specification.
    3872             :   ///
    3873             :   /// If the event type being sent is `m.room.canonical_alias` servers
    3874             :   /// SHOULD ensure that any new aliases being listed in the event are valid
    3875             :   /// per their grammar/syntax and that they point to the room ID where the
    3876             :   /// state event is to be sent. Servers do not validate aliases which are
    3877             :   /// being removed or are already present in the state event.
    3878             :   ///
    3879             :   ///
    3880             :   /// [roomId] The room to set the state in
    3881             :   ///
    3882             :   /// [eventType] The type of event to send.
    3883             :   ///
    3884             :   /// [stateKey] The state_key for the state to send. Defaults to the empty string. When
    3885             :   /// an empty string, the trailing slash on this endpoint is optional.
    3886             :   ///
    3887             :   /// [body]
    3888             :   ///
    3889             :   /// returns `event_id`:
    3890             :   /// A unique identifier for the event.
    3891           7 :   Future<String> setRoomStateWithKey(String roomId, String eventType,
    3892             :       String stateKey, Map<String, Object?> body) async {
    3893           7 :     final requestUri = Uri(
    3894             :         path:
    3895          28 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/state/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(stateKey)}');
    3896          21 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    3897          28 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3898          14 :     request.headers['content-type'] = 'application/json';
    3899          21 :     request.bodyBytes = utf8.encode(jsonEncode(body));
    3900          14 :     final response = await httpClient.send(request);
    3901          14 :     final responseBody = await response.stream.toBytes();
    3902          14 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3903           7 :     final responseString = utf8.decode(responseBody);
    3904           7 :     final json = jsonDecode(responseString);
    3905           7 :     return json['event_id'] as String;
    3906             :   }
    3907             : 
    3908             :   /// This tells the server that the user is typing for the next N
    3909             :   /// milliseconds where N is the value specified in the `timeout` key.
    3910             :   /// Alternatively, if `typing` is `false`, it tells the server that the
    3911             :   /// user has stopped typing.
    3912             :   ///
    3913             :   /// [userId] The user who has started to type.
    3914             :   ///
    3915             :   /// [roomId] The room in which the user is typing.
    3916             :   ///
    3917             :   /// [timeout] The length of time in milliseconds to mark this user as typing.
    3918             :   ///
    3919             :   /// [typing] Whether the user is typing or not. If `false`, the `timeout`
    3920             :   /// key can be omitted.
    3921           0 :   Future<void> setTyping(String userId, String roomId, bool typing,
    3922             :       {int? timeout}) async {
    3923           0 :     final requestUri = Uri(
    3924             :         path:
    3925           0 :             '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/typing/${Uri.encodeComponent(userId)}');
    3926           0 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    3927           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3928           0 :     request.headers['content-type'] = 'application/json';
    3929           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    3930           0 :       if (timeout != null) 'timeout': timeout,
    3931           0 :       'typing': typing,
    3932             :     }));
    3933           0 :     final response = await httpClient.send(request);
    3934           0 :     final responseBody = await response.stream.toBytes();
    3935           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3936           0 :     final responseString = utf8.decode(responseBody);
    3937           0 :     final json = jsonDecode(responseString);
    3938           0 :     return ignore(json);
    3939             :   }
    3940             : 
    3941             :   /// Unban a user from the room. This allows them to be invited to the room,
    3942             :   /// and join if they would otherwise be allowed to join according to its join rules.
    3943             :   ///
    3944             :   /// The caller must have the required power level in order to perform this operation.
    3945             :   ///
    3946             :   /// [roomId] The room identifier (not alias) from which the user should be unbanned.
    3947             :   ///
    3948             :   /// [reason] Optional reason to be included as the `reason` on the subsequent
    3949             :   /// membership event.
    3950             :   ///
    3951             :   /// [userId] The fully qualified user ID of the user being unbanned.
    3952           5 :   Future<void> unban(String roomId, String userId, {String? reason}) async {
    3953           5 :     final requestUri = Uri(
    3954          10 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/unban');
    3955          15 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3956          20 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3957          10 :     request.headers['content-type'] = 'application/json';
    3958          20 :     request.bodyBytes = utf8.encode(jsonEncode({
    3959           0 :       if (reason != null) 'reason': reason,
    3960           5 :       'user_id': userId,
    3961             :     }));
    3962          10 :     final response = await httpClient.send(request);
    3963          10 :     final responseBody = await response.stream.toBytes();
    3964          10 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3965           5 :     final responseString = utf8.decode(responseBody);
    3966           5 :     final json = jsonDecode(responseString);
    3967           5 :     return ignore(json);
    3968             :   }
    3969             : 
    3970             :   /// Upgrades the given room to a particular room version.
    3971             :   ///
    3972             :   /// [roomId] The ID of the room to upgrade.
    3973             :   ///
    3974             :   /// [newVersion] The new version for the room.
    3975             :   ///
    3976             :   /// returns `replacement_room`:
    3977             :   /// The ID of the new room.
    3978           0 :   Future<String> upgradeRoom(String roomId, String newVersion) async {
    3979           0 :     final requestUri = Uri(
    3980           0 :         path: '_matrix/client/v3/rooms/${Uri.encodeComponent(roomId)}/upgrade');
    3981           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    3982           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    3983           0 :     request.headers['content-type'] = 'application/json';
    3984           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    3985             :       'new_version': newVersion,
    3986             :     }));
    3987           0 :     final response = await httpClient.send(request);
    3988           0 :     final responseBody = await response.stream.toBytes();
    3989           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    3990           0 :     final responseString = utf8.decode(responseBody);
    3991           0 :     final json = jsonDecode(responseString);
    3992           0 :     return json['replacement_room'] as String;
    3993             :   }
    3994             : 
    3995             :   /// Performs a full text search across different categories.
    3996             :   ///
    3997             :   /// [nextBatch] The point to return events from. If given, this should be a
    3998             :   /// `next_batch` result from a previous call to this endpoint.
    3999             :   ///
    4000             :   /// [searchCategories] Describes which categories to search in and their criteria.
    4001           0 :   Future<SearchResults> search(Categories searchCategories,
    4002             :       {String? nextBatch}) async {
    4003           0 :     final requestUri = Uri(path: '_matrix/client/v3/search', queryParameters: {
    4004           0 :       if (nextBatch != null) 'next_batch': nextBatch,
    4005             :     });
    4006           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    4007           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4008           0 :     request.headers['content-type'] = 'application/json';
    4009           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    4010           0 :       'search_categories': searchCategories.toJson(),
    4011             :     }));
    4012           0 :     final response = await httpClient.send(request);
    4013           0 :     final responseBody = await response.stream.toBytes();
    4014           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4015           0 :     final responseString = utf8.decode(responseBody);
    4016           0 :     final json = jsonDecode(responseString);
    4017           0 :     return SearchResults.fromJson(json as Map<String, Object?>);
    4018             :   }
    4019             : 
    4020             :   /// This endpoint is used to send send-to-device events to a set of
    4021             :   /// client devices.
    4022             :   ///
    4023             :   /// [eventType] The type of event to send.
    4024             :   ///
    4025             :   /// [txnId] The [transaction ID](https://spec.matrix.org/unstable/client-server-api/#transaction-identifiers) for this event. Clients should generate an
    4026             :   /// ID unique across requests with the same access token; it will be
    4027             :   /// used by the server to ensure idempotency of requests.
    4028             :   ///
    4029             :   /// [messages] The messages to send. A map from user ID, to a map from
    4030             :   /// device ID to message body. The device ID may also be `*`,
    4031             :   /// meaning all known devices for the user.
    4032          10 :   Future<void> sendToDevice(String eventType, String txnId,
    4033             :       Map<String, Map<String, Map<String, Object?>>> messages) async {
    4034          10 :     final requestUri = Uri(
    4035             :         path:
    4036          30 :             '_matrix/client/v3/sendToDevice/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(txnId)}');
    4037          30 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    4038          40 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4039          20 :     request.headers['content-type'] = 'application/json';
    4040          40 :     request.bodyBytes = utf8.encode(jsonEncode({
    4041             :       'messages':
    4042          51 :           messages.map((k, v) => MapEntry(k, v.map((k, v) => MapEntry(k, v)))),
    4043             :     }));
    4044          20 :     final response = await httpClient.send(request);
    4045          20 :     final responseBody = await response.stream.toBytes();
    4046          21 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4047          10 :     final responseString = utf8.decode(responseBody);
    4048          10 :     final json = jsonDecode(responseString);
    4049          10 :     return ignore(json);
    4050             :   }
    4051             : 
    4052             :   /// Synchronise the client's state with the latest state on the server.
    4053             :   /// Clients use this API when they first log in to get an initial snapshot
    4054             :   /// of the state on the server, and then continue to call this API to get
    4055             :   /// incremental deltas to the state, and to receive new messages.
    4056             :   ///
    4057             :   /// *Note*: This endpoint supports lazy-loading. See [Filtering](https://spec.matrix.org/unstable/client-server-api/#filtering)
    4058             :   /// for more information. Lazy-loading members is only supported on a `StateFilter`
    4059             :   /// for this endpoint. When lazy-loading is enabled, servers MUST include the
    4060             :   /// syncing user's own membership event when they join a room, or when the
    4061             :   /// full state of rooms is requested, to aid discovering the user's avatar &
    4062             :   /// displayname.
    4063             :   ///
    4064             :   /// Further, like other members, the user's own membership event is eligible
    4065             :   /// for being considered redundant by the server. When a sync is `limited`,
    4066             :   /// the server MUST return membership events for events in the gap
    4067             :   /// (between `since` and the start of the returned timeline), regardless
    4068             :   /// as to whether or not they are redundant. This ensures that joins/leaves
    4069             :   /// and profile changes which occur during the gap are not lost.
    4070             :   ///
    4071             :   /// Note that the default behaviour of `state` is to include all membership
    4072             :   /// events, alongside other state, when lazy-loading is not enabled.
    4073             :   ///
    4074             :   /// [filter] The ID of a filter created using the filter API or a filter JSON
    4075             :   /// object encoded as a string. The server will detect whether it is
    4076             :   /// an ID or a JSON object by whether the first character is a `"{"`
    4077             :   /// open brace. Passing the JSON inline is best suited to one off
    4078             :   /// requests. Creating a filter using the filter API is recommended for
    4079             :   /// clients that reuse the same filter multiple times, for example in
    4080             :   /// long poll requests.
    4081             :   ///
    4082             :   /// See [Filtering](https://spec.matrix.org/unstable/client-server-api/#filtering) for more information.
    4083             :   ///
    4084             :   /// [since] A point in time to continue a sync from. This should be the
    4085             :   /// `next_batch` token returned by an earlier call to this endpoint.
    4086             :   ///
    4087             :   /// [fullState] Controls whether to include the full state for all rooms the user
    4088             :   /// is a member of.
    4089             :   ///
    4090             :   /// If this is set to `true`, then all state events will be returned,
    4091             :   /// even if `since` is non-empty. The timeline will still be limited
    4092             :   /// by the `since` parameter. In this case, the `timeout` parameter
    4093             :   /// will be ignored and the query will return immediately, possibly with
    4094             :   /// an empty timeline.
    4095             :   ///
    4096             :   /// If `false`, and `since` is non-empty, only state which has
    4097             :   /// changed since the point indicated by `since` will be returned.
    4098             :   ///
    4099             :   /// By default, this is `false`.
    4100             :   ///
    4101             :   /// [setPresence] Controls whether the client is automatically marked as online by
    4102             :   /// polling this API. If this parameter is omitted then the client is
    4103             :   /// automatically marked as online when it uses this API. Otherwise if
    4104             :   /// the parameter is set to "offline" then the client is not marked as
    4105             :   /// being online when it uses this API. When set to "unavailable", the
    4106             :   /// client is marked as being idle.
    4107             :   ///
    4108             :   /// [timeout] The maximum time to wait, in milliseconds, before returning this
    4109             :   /// request. If no events (or other data) become available before this
    4110             :   /// time elapses, the server will return a response with empty fields.
    4111             :   ///
    4112             :   /// By default, this is `0`, so the server will return immediately
    4113             :   /// even if the response is empty.
    4114          31 :   Future<SyncUpdate> sync(
    4115             :       {String? filter,
    4116             :       String? since,
    4117             :       bool? fullState,
    4118             :       PresenceType? setPresence,
    4119             :       int? timeout}) async {
    4120          62 :     final requestUri = Uri(path: '_matrix/client/v3/sync', queryParameters: {
    4121          31 :       if (filter != null) 'filter': filter,
    4122          31 :       if (since != null) 'since': since,
    4123           0 :       if (fullState != null) 'full_state': fullState.toString(),
    4124           0 :       if (setPresence != null) 'set_presence': setPresence.name,
    4125          62 :       if (timeout != null) 'timeout': timeout.toString(),
    4126             :     });
    4127          93 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4128         124 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4129          62 :     final response = await httpClient.send(request);
    4130          62 :     final responseBody = await response.stream.toBytes();
    4131          63 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4132          31 :     final responseString = utf8.decode(responseBody);
    4133          31 :     final json = jsonDecode(responseString);
    4134          31 :     return SyncUpdate.fromJson(json as Map<String, Object?>);
    4135             :   }
    4136             : 
    4137             :   /// Retrieve an array of third party network locations from a Matrix room
    4138             :   /// alias.
    4139             :   ///
    4140             :   /// [alias] The Matrix room alias to look up.
    4141           0 :   Future<List<Location>> queryLocationByAlias(String alias) async {
    4142             :     final requestUri =
    4143           0 :         Uri(path: '_matrix/client/v3/thirdparty/location', queryParameters: {
    4144             :       'alias': alias,
    4145             :     });
    4146           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4147           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4148           0 :     final response = await httpClient.send(request);
    4149           0 :     final responseBody = await response.stream.toBytes();
    4150           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4151           0 :     final responseString = utf8.decode(responseBody);
    4152           0 :     final json = jsonDecode(responseString);
    4153             :     return (json as List)
    4154           0 :         .map((v) => Location.fromJson(v as Map<String, Object?>))
    4155           0 :         .toList();
    4156             :   }
    4157             : 
    4158             :   /// Requesting this endpoint with a valid protocol name results in a list
    4159             :   /// of successful mapping results in a JSON array. Each result contains
    4160             :   /// objects to represent the Matrix room or rooms that represent a portal
    4161             :   /// to this third party network. Each has the Matrix room alias string,
    4162             :   /// an identifier for the particular third party network protocol, and an
    4163             :   /// object containing the network-specific fields that comprise this
    4164             :   /// identifier. It should attempt to canonicalise the identifier as much
    4165             :   /// as reasonably possible given the network type.
    4166             :   ///
    4167             :   /// [protocol] The protocol used to communicate to the third party network.
    4168             :   ///
    4169             :   /// [searchFields] One or more custom fields to help identify the third party
    4170             :   /// location.
    4171           0 :   Future<List<Location>> queryLocationByProtocol(String protocol,
    4172             :       {String? searchFields}) async {
    4173           0 :     final requestUri = Uri(
    4174             :         path:
    4175           0 :             '_matrix/client/v3/thirdparty/location/${Uri.encodeComponent(protocol)}',
    4176           0 :         queryParameters: {
    4177           0 :           if (searchFields != null) 'searchFields': searchFields,
    4178             :         });
    4179           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4180           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4181           0 :     final response = await httpClient.send(request);
    4182           0 :     final responseBody = await response.stream.toBytes();
    4183           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4184           0 :     final responseString = utf8.decode(responseBody);
    4185           0 :     final json = jsonDecode(responseString);
    4186             :     return (json as List)
    4187           0 :         .map((v) => Location.fromJson(v as Map<String, Object?>))
    4188           0 :         .toList();
    4189             :   }
    4190             : 
    4191             :   /// Fetches the metadata from the homeserver about a particular third party protocol.
    4192             :   ///
    4193             :   /// [protocol] The name of the protocol.
    4194           0 :   Future<Protocol> getProtocolMetadata(String protocol) async {
    4195           0 :     final requestUri = Uri(
    4196             :         path:
    4197           0 :             '_matrix/client/v3/thirdparty/protocol/${Uri.encodeComponent(protocol)}');
    4198           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4199           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4200           0 :     final response = await httpClient.send(request);
    4201           0 :     final responseBody = await response.stream.toBytes();
    4202           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4203           0 :     final responseString = utf8.decode(responseBody);
    4204           0 :     final json = jsonDecode(responseString);
    4205           0 :     return Protocol.fromJson(json as Map<String, Object?>);
    4206             :   }
    4207             : 
    4208             :   /// Fetches the overall metadata about protocols supported by the
    4209             :   /// homeserver. Includes both the available protocols and all fields
    4210             :   /// required for queries against each protocol.
    4211           0 :   Future<Map<String, Protocol>> getProtocols() async {
    4212           0 :     final requestUri = Uri(path: '_matrix/client/v3/thirdparty/protocols');
    4213           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4214           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4215           0 :     final response = await httpClient.send(request);
    4216           0 :     final responseBody = await response.stream.toBytes();
    4217           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4218           0 :     final responseString = utf8.decode(responseBody);
    4219           0 :     final json = jsonDecode(responseString);
    4220           0 :     return (json as Map<String, Object?>).map(
    4221           0 :         (k, v) => MapEntry(k, Protocol.fromJson(v as Map<String, Object?>)));
    4222             :   }
    4223             : 
    4224             :   /// Retrieve an array of third party users from a Matrix User ID.
    4225             :   ///
    4226             :   /// [userid] The Matrix User ID to look up.
    4227           0 :   Future<List<ThirdPartyUser>> queryUserByID(String userid) async {
    4228             :     final requestUri =
    4229           0 :         Uri(path: '_matrix/client/v3/thirdparty/user', queryParameters: {
    4230             :       'userid': userid,
    4231             :     });
    4232           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4233           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4234           0 :     final response = await httpClient.send(request);
    4235           0 :     final responseBody = await response.stream.toBytes();
    4236           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4237           0 :     final responseString = utf8.decode(responseBody);
    4238           0 :     final json = jsonDecode(responseString);
    4239             :     return (json as List)
    4240           0 :         .map((v) => ThirdPartyUser.fromJson(v as Map<String, Object?>))
    4241           0 :         .toList();
    4242             :   }
    4243             : 
    4244             :   /// Retrieve a Matrix User ID linked to a user on the third party service, given
    4245             :   /// a set of user parameters.
    4246             :   ///
    4247             :   /// [protocol] The name of the protocol.
    4248             :   ///
    4249             :   /// [fields] One or more custom fields that are passed to the AS to help identify the user.
    4250           0 :   Future<List<ThirdPartyUser>> queryUserByProtocol(String protocol,
    4251             :       {String? fields}) async {
    4252           0 :     final requestUri = Uri(
    4253             :         path:
    4254           0 :             '_matrix/client/v3/thirdparty/user/${Uri.encodeComponent(protocol)}',
    4255           0 :         queryParameters: {
    4256           0 :           if (fields != null) 'fields...': fields,
    4257             :         });
    4258           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4259           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4260           0 :     final response = await httpClient.send(request);
    4261           0 :     final responseBody = await response.stream.toBytes();
    4262           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4263           0 :     final responseString = utf8.decode(responseBody);
    4264           0 :     final json = jsonDecode(responseString);
    4265             :     return (json as List)
    4266           0 :         .map((v) => ThirdPartyUser.fromJson(v as Map<String, Object?>))
    4267           0 :         .toList();
    4268             :   }
    4269             : 
    4270             :   /// Get some account data for the client. This config is only visible to the user
    4271             :   /// that set the account data.
    4272             :   ///
    4273             :   /// [userId] The ID of the user to get account data for. The access token must be
    4274             :   /// authorized to make requests for this user ID.
    4275             :   ///
    4276             :   /// [type] The event type of the account data to get. Custom types should be
    4277             :   /// namespaced to avoid clashes.
    4278           0 :   Future<Map<String, Object?>> getAccountData(
    4279             :       String userId, String type) async {
    4280           0 :     final requestUri = Uri(
    4281             :         path:
    4282           0 :             '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/account_data/${Uri.encodeComponent(type)}');
    4283           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4284           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4285           0 :     final response = await httpClient.send(request);
    4286           0 :     final responseBody = await response.stream.toBytes();
    4287           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4288           0 :     final responseString = utf8.decode(responseBody);
    4289           0 :     final json = jsonDecode(responseString);
    4290             :     return json as Map<String, Object?>;
    4291             :   }
    4292             : 
    4293             :   /// Set some account data for the client. This config is only visible to the user
    4294             :   /// that set the account data. The config will be available to clients through the
    4295             :   /// top-level `account_data` field in the homeserver response to
    4296             :   /// [/sync](#get_matrixclientv3sync).
    4297             :   ///
    4298             :   /// [userId] The ID of the user to set account data for. The access token must be
    4299             :   /// authorized to make requests for this user ID.
    4300             :   ///
    4301             :   /// [type] The event type of the account data to set. Custom types should be
    4302             :   /// namespaced to avoid clashes.
    4303             :   ///
    4304             :   /// [content] The content of the account data.
    4305          10 :   Future<void> setAccountData(
    4306             :       String userId, String type, Map<String, Object?> content) async {
    4307          10 :     final requestUri = Uri(
    4308             :         path:
    4309          30 :             '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/account_data/${Uri.encodeComponent(type)}');
    4310          30 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    4311          40 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4312          20 :     request.headers['content-type'] = 'application/json';
    4313          30 :     request.bodyBytes = utf8.encode(jsonEncode(content));
    4314          20 :     final response = await httpClient.send(request);
    4315          20 :     final responseBody = await response.stream.toBytes();
    4316          20 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4317          10 :     final responseString = utf8.decode(responseBody);
    4318          10 :     final json = jsonDecode(responseString);
    4319          10 :     return ignore(json);
    4320             :   }
    4321             : 
    4322             :   /// Uploads a new filter definition to the homeserver.
    4323             :   /// Returns a filter ID that may be used in future requests to
    4324             :   /// restrict which events are returned to the client.
    4325             :   ///
    4326             :   /// [userId] The id of the user uploading the filter. The access token must be authorized to make requests for this user id.
    4327             :   ///
    4328             :   /// [filter] The filter to upload.
    4329             :   ///
    4330             :   /// returns `filter_id`:
    4331             :   /// The ID of the filter that was created. Cannot start
    4332             :   /// with a `{` as this character is used to determine
    4333             :   /// if the filter provided is inline JSON or a previously
    4334             :   /// declared filter by homeservers on some APIs.
    4335          31 :   Future<String> defineFilter(String userId, Filter filter) async {
    4336          31 :     final requestUri = Uri(
    4337          62 :         path: '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/filter');
    4338          93 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    4339         124 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4340          62 :     request.headers['content-type'] = 'application/json';
    4341         124 :     request.bodyBytes = utf8.encode(jsonEncode(filter.toJson()));
    4342          62 :     final response = await httpClient.send(request);
    4343          62 :     final responseBody = await response.stream.toBytes();
    4344          62 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4345          31 :     final responseString = utf8.decode(responseBody);
    4346          31 :     final json = jsonDecode(responseString);
    4347          31 :     return json['filter_id'] as String;
    4348             :   }
    4349             : 
    4350             :   ///
    4351             :   ///
    4352             :   /// [userId] The user ID to download a filter for.
    4353             :   ///
    4354             :   /// [filterId] The filter ID to download.
    4355           0 :   Future<Filter> getFilter(String userId, String filterId) async {
    4356           0 :     final requestUri = Uri(
    4357             :         path:
    4358           0 :             '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/filter/${Uri.encodeComponent(filterId)}');
    4359           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4360           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4361           0 :     final response = await httpClient.send(request);
    4362           0 :     final responseBody = await response.stream.toBytes();
    4363           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4364           0 :     final responseString = utf8.decode(responseBody);
    4365           0 :     final json = jsonDecode(responseString);
    4366           0 :     return Filter.fromJson(json as Map<String, Object?>);
    4367             :   }
    4368             : 
    4369             :   /// Gets an OpenID token object that the requester may supply to another
    4370             :   /// service to verify their identity in Matrix. The generated token is only
    4371             :   /// valid for exchanging for user information from the federation API for
    4372             :   /// OpenID.
    4373             :   ///
    4374             :   /// The access token generated is only valid for the OpenID API. It cannot
    4375             :   /// be used to request another OpenID access token or call `/sync`, for
    4376             :   /// example.
    4377             :   ///
    4378             :   /// [userId] The user to request an OpenID token for. Should be the user who
    4379             :   /// is authenticated for the request.
    4380             :   ///
    4381             :   /// [body] An empty object. Reserved for future expansion.
    4382           0 :   Future<OpenIdCredentials> requestOpenIdToken(
    4383             :       String userId, Map<String, Object?> body) async {
    4384           0 :     final requestUri = Uri(
    4385             :         path:
    4386           0 :             '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/openid/request_token');
    4387           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    4388           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4389           0 :     request.headers['content-type'] = 'application/json';
    4390           0 :     request.bodyBytes = utf8.encode(jsonEncode(body));
    4391           0 :     final response = await httpClient.send(request);
    4392           0 :     final responseBody = await response.stream.toBytes();
    4393           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4394           0 :     final responseString = utf8.decode(responseBody);
    4395           0 :     final json = jsonDecode(responseString);
    4396           0 :     return OpenIdCredentials.fromJson(json as Map<String, Object?>);
    4397             :   }
    4398             : 
    4399             :   /// Get some account data for the client on a given room. This config is only
    4400             :   /// visible to the user that set the account data.
    4401             :   ///
    4402             :   /// [userId] The ID of the user to get account data for. The access token must be
    4403             :   /// authorized to make requests for this user ID.
    4404             :   ///
    4405             :   /// [roomId] The ID of the room to get account data for.
    4406             :   ///
    4407             :   /// [type] The event type of the account data to get. Custom types should be
    4408             :   /// namespaced to avoid clashes.
    4409           0 :   Future<Map<String, Object?>> getAccountDataPerRoom(
    4410             :       String userId, String roomId, String type) async {
    4411           0 :     final requestUri = Uri(
    4412             :         path:
    4413           0 :             '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/account_data/${Uri.encodeComponent(type)}');
    4414           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4415           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4416           0 :     final response = await httpClient.send(request);
    4417           0 :     final responseBody = await response.stream.toBytes();
    4418           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4419           0 :     final responseString = utf8.decode(responseBody);
    4420           0 :     final json = jsonDecode(responseString);
    4421             :     return json as Map<String, Object?>;
    4422             :   }
    4423             : 
    4424             :   /// Set some account data for the client on a given room. This config is only
    4425             :   /// visible to the user that set the account data. The config will be delivered to
    4426             :   /// clients in the per-room entries via [/sync](#get_matrixclientv3sync).
    4427             :   ///
    4428             :   /// [userId] The ID of the user to set account data for. The access token must be
    4429             :   /// authorized to make requests for this user ID.
    4430             :   ///
    4431             :   /// [roomId] The ID of the room to set account data on.
    4432             :   ///
    4433             :   /// [type] The event type of the account data to set. Custom types should be
    4434             :   /// namespaced to avoid clashes.
    4435             :   ///
    4436             :   /// [content] The content of the account data.
    4437           3 :   Future<void> setAccountDataPerRoom(String userId, String roomId, String type,
    4438             :       Map<String, Object?> content) async {
    4439           3 :     final requestUri = Uri(
    4440             :         path:
    4441          12 :             '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/account_data/${Uri.encodeComponent(type)}');
    4442           9 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    4443          12 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4444           6 :     request.headers['content-type'] = 'application/json';
    4445           9 :     request.bodyBytes = utf8.encode(jsonEncode(content));
    4446           6 :     final response = await httpClient.send(request);
    4447           6 :     final responseBody = await response.stream.toBytes();
    4448           6 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4449           3 :     final responseString = utf8.decode(responseBody);
    4450           3 :     final json = jsonDecode(responseString);
    4451           3 :     return ignore(json);
    4452             :   }
    4453             : 
    4454             :   /// List the tags set by a user on a room.
    4455             :   ///
    4456             :   /// [userId] The id of the user to get tags for. The access token must be
    4457             :   /// authorized to make requests for this user ID.
    4458             :   ///
    4459             :   /// [roomId] The ID of the room to get tags for.
    4460             :   ///
    4461             :   /// returns `tags`:
    4462             :   ///
    4463           0 :   Future<Map<String, Tag>?> getRoomTags(String userId, String roomId) async {
    4464           0 :     final requestUri = Uri(
    4465             :         path:
    4466           0 :             '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/tags');
    4467           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4468           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4469           0 :     final response = await httpClient.send(request);
    4470           0 :     final responseBody = await response.stream.toBytes();
    4471           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4472           0 :     final responseString = utf8.decode(responseBody);
    4473           0 :     final json = jsonDecode(responseString);
    4474           0 :     return ((v) => v != null
    4475             :         ? (v as Map<String, Object?>)
    4476           0 :             .map((k, v) => MapEntry(k, Tag.fromJson(v as Map<String, Object?>)))
    4477           0 :         : null)(json['tags']);
    4478             :   }
    4479             : 
    4480             :   /// Remove a tag from the room.
    4481             :   ///
    4482             :   /// [userId] The id of the user to remove a tag for. The access token must be
    4483             :   /// authorized to make requests for this user ID.
    4484             :   ///
    4485             :   /// [roomId] The ID of the room to remove a tag from.
    4486             :   ///
    4487             :   /// [tag] The tag to remove.
    4488           2 :   Future<void> deleteRoomTag(String userId, String roomId, String tag) async {
    4489           2 :     final requestUri = Uri(
    4490             :         path:
    4491           8 :             '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/tags/${Uri.encodeComponent(tag)}');
    4492           6 :     final request = Request('DELETE', baseUri!.resolveUri(requestUri));
    4493           8 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4494           4 :     final response = await httpClient.send(request);
    4495           4 :     final responseBody = await response.stream.toBytes();
    4496           4 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4497           2 :     final responseString = utf8.decode(responseBody);
    4498           2 :     final json = jsonDecode(responseString);
    4499           2 :     return ignore(json);
    4500             :   }
    4501             : 
    4502             :   /// Add a tag to the room.
    4503             :   ///
    4504             :   /// [userId] The id of the user to add a tag for. The access token must be
    4505             :   /// authorized to make requests for this user ID.
    4506             :   ///
    4507             :   /// [roomId] The ID of the room to add a tag to.
    4508             :   ///
    4509             :   /// [tag] The tag to add.
    4510             :   ///
    4511             :   /// [order] A number in a range `[0,1]` describing a relative
    4512             :   /// position of the room under the given tag.
    4513           2 :   Future<void> setRoomTag(String userId, String roomId, String tag,
    4514             :       {double? order,
    4515             :       Map<String, Object?> additionalProperties = const {}}) async {
    4516           2 :     final requestUri = Uri(
    4517             :         path:
    4518           8 :             '_matrix/client/v3/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/tags/${Uri.encodeComponent(tag)}');
    4519           6 :     final request = Request('PUT', baseUri!.resolveUri(requestUri));
    4520           8 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4521           4 :     request.headers['content-type'] = 'application/json';
    4522           8 :     request.bodyBytes = utf8.encode(jsonEncode({
    4523             :       ...additionalProperties,
    4524           2 :       if (order != null) 'order': order,
    4525             :     }));
    4526           4 :     final response = await httpClient.send(request);
    4527           4 :     final responseBody = await response.stream.toBytes();
    4528           4 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4529           2 :     final responseString = utf8.decode(responseBody);
    4530           2 :     final json = jsonDecode(responseString);
    4531           2 :     return ignore(json);
    4532             :   }
    4533             : 
    4534             :   /// Performs a search for users. The homeserver may
    4535             :   /// determine which subset of users are searched, however the homeserver
    4536             :   /// MUST at a minimum consider the users the requesting user shares a
    4537             :   /// room with and those who reside in public rooms (known to the homeserver).
    4538             :   /// The search MUST consider local users to the homeserver, and SHOULD
    4539             :   /// query remote users as part of the search.
    4540             :   ///
    4541             :   /// The search is performed case-insensitively on user IDs and display
    4542             :   /// names preferably using a collation determined based upon the
    4543             :   /// `Accept-Language` header provided in the request, if present.
    4544             :   ///
    4545             :   /// [limit] The maximum number of results to return. Defaults to 10.
    4546             :   ///
    4547             :   /// [searchTerm] The term to search for
    4548           0 :   Future<SearchUserDirectoryResponse> searchUserDirectory(String searchTerm,
    4549             :       {int? limit}) async {
    4550           0 :     final requestUri = Uri(path: '_matrix/client/v3/user_directory/search');
    4551           0 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    4552           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4553           0 :     request.headers['content-type'] = 'application/json';
    4554           0 :     request.bodyBytes = utf8.encode(jsonEncode({
    4555           0 :       if (limit != null) 'limit': limit,
    4556           0 :       'search_term': searchTerm,
    4557             :     }));
    4558           0 :     final response = await httpClient.send(request);
    4559           0 :     final responseBody = await response.stream.toBytes();
    4560           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4561           0 :     final responseString = utf8.decode(responseBody);
    4562           0 :     final json = jsonDecode(responseString);
    4563           0 :     return SearchUserDirectoryResponse.fromJson(json as Map<String, Object?>);
    4564             :   }
    4565             : 
    4566             :   /// This API provides credentials for the client to use when initiating
    4567             :   /// calls.
    4568           0 :   Future<TurnServerCredentials> getTurnServer() async {
    4569           0 :     final requestUri = Uri(path: '_matrix/client/v3/voip/turnServer');
    4570           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4571           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4572           0 :     final response = await httpClient.send(request);
    4573           0 :     final responseBody = await response.stream.toBytes();
    4574           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4575           0 :     final responseString = utf8.decode(responseBody);
    4576           0 :     final json = jsonDecode(responseString);
    4577           0 :     return TurnServerCredentials.fromJson(json as Map<String, Object?>);
    4578             :   }
    4579             : 
    4580             :   /// Gets the versions of the specification supported by the server.
    4581             :   ///
    4582             :   /// Values will take the form `vX.Y` or `rX.Y.Z` in historical cases. See
    4583             :   /// [the Specification Versioning](../#specification-versions) for more
    4584             :   /// information.
    4585             :   ///
    4586             :   /// The server may additionally advertise experimental features it supports
    4587             :   /// through `unstable_features`. These features should be namespaced and
    4588             :   /// may optionally include version information within their name if desired.
    4589             :   /// Features listed here are not for optionally toggling parts of the Matrix
    4590             :   /// specification and should only be used to advertise support for a feature
    4591             :   /// which has not yet landed in the spec. For example, a feature currently
    4592             :   /// undergoing the proposal process may appear here and eventually be taken
    4593             :   /// off this list once the feature lands in the spec and the server deems it
    4594             :   /// reasonable to do so. Servers may wish to keep advertising features here
    4595             :   /// after they've been released into the spec to give clients a chance to
    4596             :   /// upgrade appropriately. Additionally, clients should avoid using unstable
    4597             :   /// features in their stable releases.
    4598          33 :   Future<GetVersionsResponse> getVersions() async {
    4599          33 :     final requestUri = Uri(path: '_matrix/client/versions');
    4600          99 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4601          66 :     final response = await httpClient.send(request);
    4602          66 :     final responseBody = await response.stream.toBytes();
    4603          67 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4604          33 :     final responseString = utf8.decode(responseBody);
    4605          33 :     final json = jsonDecode(responseString);
    4606          33 :     return GetVersionsResponse.fromJson(json as Map<String, Object?>);
    4607             :   }
    4608             : 
    4609             :   /// This endpoint allows clients to retrieve the configuration of the content
    4610             :   /// repository, such as upload limitations.
    4611             :   /// Clients SHOULD use this as a guide when using content repository endpoints.
    4612             :   /// All values are intentionally left optional. Clients SHOULD follow
    4613             :   /// the advice given in the field description when the field is not available.
    4614             :   ///
    4615             :   /// **NOTE:** Both clients and server administrators should be aware that proxies
    4616             :   /// between the client and the server may affect the apparent behaviour of content
    4617             :   /// repository APIs, for example, proxies may enforce a lower upload size limit
    4618             :   /// than is advertised by the server on this endpoint.
    4619           4 :   Future<ServerConfig> getConfig() async {
    4620           4 :     final requestUri = Uri(path: '_matrix/media/v3/config');
    4621          12 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4622          16 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4623           8 :     final response = await httpClient.send(request);
    4624           8 :     final responseBody = await response.stream.toBytes();
    4625           8 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4626           4 :     final responseString = utf8.decode(responseBody);
    4627           4 :     final json = jsonDecode(responseString);
    4628           4 :     return ServerConfig.fromJson(json as Map<String, Object?>);
    4629             :   }
    4630             : 
    4631             :   ///
    4632             :   ///
    4633             :   /// [serverName] The server name from the `mxc://` URI (the authoritory component)
    4634             :   ///
    4635             :   ///
    4636             :   /// [mediaId] The media ID from the `mxc://` URI (the path component)
    4637             :   ///
    4638             :   ///
    4639             :   /// [allowRemote] Indicates to the server that it should not attempt to fetch the media if it is deemed
    4640             :   /// remote. This is to prevent routing loops where the server contacts itself. Defaults to
    4641             :   /// true if not provided.
    4642             :   ///
    4643           0 :   Future<FileResponse> getContent(String serverName, String mediaId,
    4644             :       {bool? allowRemote}) async {
    4645           0 :     final requestUri = Uri(
    4646             :         path:
    4647           0 :             '_matrix/media/v3/download/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}',
    4648           0 :         queryParameters: {
    4649           0 :           if (allowRemote != null) 'allow_remote': allowRemote.toString(),
    4650             :         });
    4651           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4652           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4653           0 :     final response = await httpClient.send(request);
    4654           0 :     final responseBody = await response.stream.toBytes();
    4655           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4656           0 :     return FileResponse(
    4657           0 :         contentType: response.headers['content-type'], data: responseBody);
    4658             :   }
    4659             : 
    4660             :   /// This will download content from the content repository (same as
    4661             :   /// the previous endpoint) but replace the target file name with the one
    4662             :   /// provided by the caller.
    4663             :   ///
    4664             :   /// [serverName] The server name from the `mxc://` URI (the authoritory component)
    4665             :   ///
    4666             :   ///
    4667             :   /// [mediaId] The media ID from the `mxc://` URI (the path component)
    4668             :   ///
    4669             :   ///
    4670             :   /// [fileName] A filename to give in the `Content-Disposition` header.
    4671             :   ///
    4672             :   /// [allowRemote] Indicates to the server that it should not attempt to fetch the media if it is deemed
    4673             :   /// remote. This is to prevent routing loops where the server contacts itself. Defaults to
    4674             :   /// true if not provided.
    4675             :   ///
    4676           0 :   Future<FileResponse> getContentOverrideName(
    4677             :       String serverName, String mediaId, String fileName,
    4678             :       {bool? allowRemote}) async {
    4679           0 :     final requestUri = Uri(
    4680             :         path:
    4681           0 :             '_matrix/media/v3/download/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}/${Uri.encodeComponent(fileName)}',
    4682           0 :         queryParameters: {
    4683           0 :           if (allowRemote != null) 'allow_remote': allowRemote.toString(),
    4684             :         });
    4685           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4686           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4687           0 :     final response = await httpClient.send(request);
    4688           0 :     final responseBody = await response.stream.toBytes();
    4689           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4690           0 :     return FileResponse(
    4691           0 :         contentType: response.headers['content-type'], data: responseBody);
    4692             :   }
    4693             : 
    4694             :   /// Get information about a URL for the client. Typically this is called when a
    4695             :   /// client sees a URL in a message and wants to render a preview for the user.
    4696             :   ///
    4697             :   /// **Note:**
    4698             :   /// Clients should consider avoiding this endpoint for URLs posted in encrypted
    4699             :   /// rooms. Encrypted rooms often contain more sensitive information the users
    4700             :   /// do not want to share with the homeserver, and this can mean that the URLs
    4701             :   /// being shared should also not be shared with the homeserver.
    4702             :   ///
    4703             :   /// [url] The URL to get a preview of.
    4704             :   ///
    4705             :   /// [ts] The preferred point in time to return a preview for. The server may
    4706             :   /// return a newer version if it does not have the requested version
    4707             :   /// available.
    4708           0 :   Future<GetUrlPreviewResponse> getUrlPreview(Uri url, {int? ts}) async {
    4709             :     final requestUri =
    4710           0 :         Uri(path: '_matrix/media/v3/preview_url', queryParameters: {
    4711           0 :       'url': url.toString(),
    4712           0 :       if (ts != null) 'ts': ts.toString(),
    4713             :     });
    4714           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4715           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4716           0 :     final response = await httpClient.send(request);
    4717           0 :     final responseBody = await response.stream.toBytes();
    4718           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4719           0 :     final responseString = utf8.decode(responseBody);
    4720           0 :     final json = jsonDecode(responseString);
    4721           0 :     return GetUrlPreviewResponse.fromJson(json as Map<String, Object?>);
    4722             :   }
    4723             : 
    4724             :   /// Download a thumbnail of content from the content repository.
    4725             :   /// See the [Thumbnails](https://spec.matrix.org/unstable/client-server-api/#thumbnails) section for more information.
    4726             :   ///
    4727             :   /// [serverName] The server name from the `mxc://` URI (the authoritory component)
    4728             :   ///
    4729             :   ///
    4730             :   /// [mediaId] The media ID from the `mxc://` URI (the path component)
    4731             :   ///
    4732             :   ///
    4733             :   /// [width] The *desired* width of the thumbnail. The actual thumbnail may be
    4734             :   /// larger than the size specified.
    4735             :   ///
    4736             :   /// [height] The *desired* height of the thumbnail. The actual thumbnail may be
    4737             :   /// larger than the size specified.
    4738             :   ///
    4739             :   /// [method] The desired resizing method. See the [Thumbnails](https://spec.matrix.org/unstable/client-server-api/#thumbnails)
    4740             :   /// section for more information.
    4741             :   ///
    4742             :   /// [allowRemote] Indicates to the server that it should not attempt to fetch
    4743             :   /// the media if it is deemed remote. This is to prevent routing loops
    4744             :   /// where the server contacts itself. Defaults to true if not provided.
    4745           0 :   Future<FileResponse> getContentThumbnail(
    4746             :       String serverName, String mediaId, int width, int height,
    4747             :       {Method? method, bool? allowRemote}) async {
    4748           0 :     final requestUri = Uri(
    4749             :         path:
    4750           0 :             '_matrix/media/v3/thumbnail/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}',
    4751           0 :         queryParameters: {
    4752           0 :           'width': width.toString(),
    4753           0 :           'height': height.toString(),
    4754           0 :           if (method != null) 'method': method.name,
    4755           0 :           if (allowRemote != null) 'allow_remote': allowRemote.toString(),
    4756             :         });
    4757           0 :     final request = Request('GET', baseUri!.resolveUri(requestUri));
    4758           0 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4759           0 :     final response = await httpClient.send(request);
    4760           0 :     final responseBody = await response.stream.toBytes();
    4761           0 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4762           0 :     return FileResponse(
    4763           0 :         contentType: response.headers['content-type'], data: responseBody);
    4764             :   }
    4765             : 
    4766             :   ///
    4767             :   ///
    4768             :   /// [filename] The name of the file being uploaded
    4769             :   ///
    4770             :   /// [content] The content to be uploaded.
    4771             :   ///
    4772             :   /// [contentType] The content type of the file being uploaded
    4773             :   ///
    4774             :   /// returns `content_uri`:
    4775             :   /// The [MXC URI](https://spec.matrix.org/unstable/client-server-api/#matrix-content-mxc-uris) to the uploaded content.
    4776           4 :   Future<Uri> uploadContent(Uint8List content,
    4777             :       {String? filename, String? contentType}) async {
    4778           8 :     final requestUri = Uri(path: '_matrix/media/v3/upload', queryParameters: {
    4779           4 :       if (filename != null) 'filename': filename,
    4780             :     });
    4781          12 :     final request = Request('POST', baseUri!.resolveUri(requestUri));
    4782          16 :     request.headers['authorization'] = 'Bearer ${bearerToken!}';
    4783           8 :     if (contentType != null) request.headers['content-type'] = contentType;
    4784           4 :     request.bodyBytes = content;
    4785           8 :     final response = await httpClient.send(request);
    4786           8 :     final responseBody = await response.stream.toBytes();
    4787           8 :     if (response.statusCode != 200) unexpectedResponse(response, responseBody);
    4788           4 :     final responseString = utf8.decode(responseBody);
    4789           4 :     final json = jsonDecode(responseString);
    4790           8 :     return Uri.parse(json['content_uri'] as String);
    4791             :   }
    4792             : }

Generated by: LCOV version 1.14