feat: BREAKING CHANGE v1.11 matrix-spec endpoints

This commit is contained in:
td 2024-09-19 14:16:49 +02:00
parent ca41a963e3
commit 140db616d9
No known key found for this signature in database
GPG Key ID: 62A30523D4D6CE28
9 changed files with 1464 additions and 590 deletions

View File

@ -73,6 +73,7 @@ export 'src/utils/sync_update_extension.dart';
export 'src/utils/to_device_event.dart'; export 'src/utils/to_device_event.dart';
export 'src/utils/uia_request.dart'; export 'src/utils/uia_request.dart';
export 'src/utils/uri_extension.dart'; export 'src/utils/uri_extension.dart';
export 'src/models/login_type.dart';
export 'msc_extensions/extension_recent_emoji/recent_emoji.dart'; export 'msc_extensions/extension_recent_emoji/recent_emoji.dart';
export 'msc_extensions/msc_3935_cute_events/msc_3935_cute_events.dart'; export 'msc_extensions/msc_3935_cute_events/msc_3935_cute_events.dart';

File diff suppressed because it is too large Load Diff

View File

@ -84,6 +84,195 @@ class DiscoveryInformation {
Map<String, Map<String, Object?>> additionalProperties; Map<String, Map<String, Object?>> additionalProperties;
} }
///
@_NameSource('generated')
@EnhancedEnum()
enum Role {
@EnhancedEnumValue(name: 'm.role.admin')
mRoleAdmin,
@EnhancedEnumValue(name: 'm.role.security')
mRoleSecurity
}
/// A way to contact the server administrator.
@_NameSource('spec')
class Contact {
Contact({
this.emailAddress,
this.matrixId,
required this.role,
});
Contact.fromJson(Map<String, Object?> json)
: emailAddress =
((v) => v != null ? v as String : null)(json['email_address']),
matrixId = ((v) => v != null ? v as String : null)(json['matrix_id']),
role = Role.values.fromString(json['role'] as String)!;
Map<String, Object?> toJson() {
final emailAddress = this.emailAddress;
final matrixId = this.matrixId;
return {
if (emailAddress != null) 'email_address': emailAddress,
if (matrixId != null) 'matrix_id': matrixId,
'role': role.name,
};
}
/// An email address to reach the administrator.
///
/// At least one of `matrix_id` or `email_address` is
/// required.
String? emailAddress;
/// A [Matrix User ID](https://spec.matrix.org/unstable/appendices/#user-identifiers)
/// representing the administrator.
///
/// It could be an account registered on a different
/// homeserver so the administrator can be contacted
/// when the homeserver is down.
///
/// At least one of `matrix_id` or `email_address` is
/// required.
String? matrixId;
/// An informal description of what the contact methods
/// are used for.
///
/// `m.role.admin` is a catch-all role for any queries
/// and `m.role.security` is intended for sensitive
/// requests.
///
/// Unspecified roles are permitted through the use of
/// [Namespaced Identifiers](https://spec.matrix.org/unstable/appendices/#common-namespaced-identifier-grammar).
Role role;
}
///
@_NameSource('generated')
class GetWellknownSupportResponse {
GetWellknownSupportResponse({
this.contacts,
this.supportPage,
});
GetWellknownSupportResponse.fromJson(Map<String, Object?> json)
: contacts = ((v) => v != null
? (v as List)
.map((v) => Contact.fromJson(v as Map<String, Object?>))
.toList()
: null)(json['contacts']),
supportPage =
((v) => v != null ? v as String : null)(json['support_page']);
Map<String, Object?> toJson() {
final contacts = this.contacts;
final supportPage = this.supportPage;
return {
if (contacts != null)
'contacts': contacts.map((v) => v.toJson()).toList(),
if (supportPage != null) 'support_page': supportPage,
};
}
/// Ways to contact the server administrator.
///
/// At least one of `contacts` or `support_page` is required.
/// If only `contacts` is set, it must contain at least one
/// item.
List<Contact>? contacts;
/// The URL of a page to give users help specific to the
/// homeserver, like extra login/registration steps.
///
/// At least one of `contacts` or `support_page` is required.
String? supportPage;
}
///
@_NameSource('generated')
class GenerateLoginTokenResponse {
GenerateLoginTokenResponse({
required this.expiresInMs,
required this.loginToken,
});
GenerateLoginTokenResponse.fromJson(Map<String, Object?> json)
: expiresInMs = json['expires_in_ms'] as int,
loginToken = json['login_token'] as String;
Map<String, Object?> toJson() => {
'expires_in_ms': expiresInMs,
'login_token': loginToken,
};
/// The time remaining in milliseconds until the homeserver will no longer accept the token. `120000`
/// (2 minutes) is recommended as a default.
int expiresInMs;
/// The login token for the `m.login.token` login flow.
String loginToken;
}
///
@_NameSource('rule override generated')
class MediaConfig {
MediaConfig({
this.mUploadSize,
});
MediaConfig.fromJson(Map<String, Object?> json)
: mUploadSize =
((v) => v != null ? v as int : null)(json['m.upload.size']);
Map<String, Object?> toJson() {
final mUploadSize = this.mUploadSize;
return {
if (mUploadSize != null) 'm.upload.size': mUploadSize,
};
}
/// The maximum size an upload can be in bytes.
/// Clients SHOULD use this as a guide when uploading content.
/// If not listed or null, the size limit should be treated as unknown.
int? mUploadSize;
}
///
@_NameSource('rule override generated')
class PreviewForUrl {
PreviewForUrl({
this.matrixImageSize,
this.ogImage,
});
PreviewForUrl.fromJson(Map<String, Object?> json)
: matrixImageSize =
((v) => v != null ? v as int : null)(json['matrix:image:size']),
ogImage = ((v) =>
v != null ? Uri.parse(v as String) : null)(json['og:image']);
Map<String, Object?> toJson() {
final matrixImageSize = this.matrixImageSize;
final ogImage = this.ogImage;
return {
if (matrixImageSize != null) 'matrix:image:size': matrixImageSize,
if (ogImage != null) 'og:image': ogImage.toString(),
};
}
/// The byte-size of the image. Omitted if there is no image attached.
int? matrixImageSize;
/// An [`mxc://` URI](https://spec.matrix.org/unstable/client-server-api/#matrix-content-mxc-uris) to the image. Omitted if there is no image.
Uri? ogImage;
}
///
@_NameSource('generated')
@EnhancedEnum()
enum Method {
@EnhancedEnumValue(name: 'crop')
crop,
@EnhancedEnumValue(name: 'scale')
scale
}
/// ///
@_NameSource('spec') @_NameSource('spec')
class PublicRoomsChunk { class PublicRoomsChunk {
@ -170,13 +359,13 @@ class PublicRoomsChunk {
/// ///
@_NameSource('spec') @_NameSource('spec')
class ChildRoomsChunk { class SpaceHierarchyRoomsChunk {
ChildRoomsChunk({ SpaceHierarchyRoomsChunk({
required this.childrenState, required this.childrenState,
this.roomType, this.roomType,
}); });
ChildRoomsChunk.fromJson(Map<String, Object?> json) SpaceHierarchyRoomsChunk.fromJson(Map<String, Object?> json)
: childrenState = (json['children_state'] as List) : childrenState = (json['children_state'] as List)
.map((v) => ChildrenState.fromJson(v as Map<String, Object?>)) .map((v) => ChildrenState.fromJson(v as Map<String, Object?>))
.toList(), .toList(),
@ -201,7 +390,7 @@ class ChildRoomsChunk {
/// ///
@_NameSource('rule override generated') @_NameSource('rule override generated')
class SpaceRoomsChunk implements PublicRoomsChunk, ChildRoomsChunk { class SpaceRoomsChunk implements PublicRoomsChunk, SpaceHierarchyRoomsChunk {
SpaceRoomsChunk({ SpaceRoomsChunk({
this.avatarUrl, this.avatarUrl,
this.canonicalAlias, this.canonicalAlias,
@ -352,6 +541,7 @@ class GetRelatingEventsResponse {
required this.chunk, required this.chunk,
this.nextBatch, this.nextBatch,
this.prevBatch, this.prevBatch,
this.recursionDepth,
}); });
GetRelatingEventsResponse.fromJson(Map<String, Object?> json) GetRelatingEventsResponse.fromJson(Map<String, Object?> json)
@ -359,91 +549,18 @@ class GetRelatingEventsResponse {
.map((v) => MatrixEvent.fromJson(v as Map<String, Object?>)) .map((v) => MatrixEvent.fromJson(v as Map<String, Object?>))
.toList(), .toList(),
nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']), nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']),
prevBatch = ((v) => v != null ? v as String : null)(json['prev_batch']); prevBatch = ((v) => v != null ? v as String : null)(json['prev_batch']),
Map<String, Object?> toJson() { recursionDepth =
final nextBatch = this.nextBatch; ((v) => v != null ? v as int : null)(json['recursion_depth']);
final prevBatch = this.prevBatch;
return {
'chunk': chunk.map((v) => v.toJson()).toList(),
if (nextBatch != null) 'next_batch': nextBatch,
if (prevBatch != null) 'prev_batch': prevBatch,
};
}
/// The child events of the requested event, ordered topologically most-recent first.
List<MatrixEvent> chunk;
/// An opaque string representing a pagination token. The absence of this token
/// means there are no more results to fetch and the client should stop paginating.
String? nextBatch;
/// An opaque string representing a pagination token. The absence of this token
/// means this is the start of the result set, i.e. this is the first batch/page.
String? prevBatch;
}
///
@_NameSource('generated')
class GetRelatingEventsWithRelTypeResponse {
GetRelatingEventsWithRelTypeResponse({
required this.chunk,
this.nextBatch,
this.prevBatch,
});
GetRelatingEventsWithRelTypeResponse.fromJson(Map<String, Object?> json)
: chunk = (json['chunk'] as List)
.map((v) => MatrixEvent.fromJson(v as Map<String, Object?>))
.toList(),
nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']),
prevBatch = ((v) => v != null ? v as String : null)(json['prev_batch']);
Map<String, Object?> toJson() {
final nextBatch = this.nextBatch;
final prevBatch = this.prevBatch;
return {
'chunk': chunk.map((v) => v.toJson()).toList(),
if (nextBatch != null) 'next_batch': nextBatch,
if (prevBatch != null) 'prev_batch': prevBatch,
};
}
/// The child events of the requested event, ordered topologically
/// most-recent first. The events returned will match the `relType`
/// supplied in the URL.
List<MatrixEvent> chunk;
/// An opaque string representing a pagination token. The absence of this token
/// means there are no more results to fetch and the client should stop paginating.
String? nextBatch;
/// An opaque string representing a pagination token. The absence of this token
/// means this is the start of the result set, i.e. this is the first batch/page.
String? prevBatch;
}
///
@_NameSource('generated')
class GetRelatingEventsWithRelTypeAndEventTypeResponse {
GetRelatingEventsWithRelTypeAndEventTypeResponse({
required this.chunk,
this.nextBatch,
this.prevBatch,
});
GetRelatingEventsWithRelTypeAndEventTypeResponse.fromJson(
Map<String, Object?> json)
: chunk = (json['chunk'] as List)
.map((v) => MatrixEvent.fromJson(v as Map<String, Object?>))
.toList(),
nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']),
prevBatch = ((v) => v != null ? v as String : null)(json['prev_batch']);
Map<String, Object?> toJson() { Map<String, Object?> toJson() {
final nextBatch = this.nextBatch; final nextBatch = this.nextBatch;
final prevBatch = this.prevBatch; final prevBatch = this.prevBatch;
final recursionDepth = this.recursionDepth;
return { return {
'chunk': chunk.map((v) => v.toJson()).toList(), 'chunk': chunk.map((v) => v.toJson()).toList(),
if (nextBatch != null) 'next_batch': nextBatch, if (nextBatch != null) 'next_batch': nextBatch,
if (prevBatch != null) 'prev_batch': prevBatch, if (prevBatch != null) 'prev_batch': prevBatch,
if (recursionDepth != null) 'recursion_depth': recursionDepth,
}; };
} }
@ -459,6 +576,110 @@ class GetRelatingEventsWithRelTypeAndEventTypeResponse {
/// An opaque string representing a pagination token. The absence of this token /// An opaque string representing a pagination token. The absence of this token
/// means this is the start of the result set, i.e. this is the first batch/page. /// means this is the start of the result set, i.e. this is the first batch/page.
String? prevBatch; String? prevBatch;
/// If the `recurse` parameter was supplied by the client, this response field is
/// mandatory and gives the actual depth to which the server recursed. If the client
/// did not specify the `recurse` parameter, this field must be absent.
int? recursionDepth;
}
///
@_NameSource('generated')
class GetRelatingEventsWithRelTypeResponse {
GetRelatingEventsWithRelTypeResponse({
required this.chunk,
this.nextBatch,
this.prevBatch,
this.recursionDepth,
});
GetRelatingEventsWithRelTypeResponse.fromJson(Map<String, Object?> json)
: chunk = (json['chunk'] as List)
.map((v) => MatrixEvent.fromJson(v as Map<String, Object?>))
.toList(),
nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']),
prevBatch = ((v) => v != null ? v as String : null)(json['prev_batch']),
recursionDepth =
((v) => v != null ? v as int : null)(json['recursion_depth']);
Map<String, Object?> toJson() {
final nextBatch = this.nextBatch;
final prevBatch = this.prevBatch;
final recursionDepth = this.recursionDepth;
return {
'chunk': chunk.map((v) => v.toJson()).toList(),
if (nextBatch != null) 'next_batch': nextBatch,
if (prevBatch != null) 'prev_batch': prevBatch,
if (recursionDepth != null) 'recursion_depth': recursionDepth,
};
}
/// The child events of the requested event, ordered topologically most-recent
/// first. The events returned will match the `relType` and `eventType` supplied
/// in the URL.
List<MatrixEvent> chunk;
/// An opaque string representing a pagination token. The absence of this token
/// means there are no more results to fetch and the client should stop paginating.
String? nextBatch;
/// An opaque string representing a pagination token. The absence of this token
/// means this is the start of the result set, i.e. this is the first batch/page.
String? prevBatch;
/// If the `recurse` parameter was supplied by the client, this response field is
/// mandatory and gives the actual depth to which the server recursed. If the client
/// did not specify the `recurse` parameter, this field must be absent.
int? recursionDepth;
}
///
@_NameSource('generated')
class GetRelatingEventsWithRelTypeAndEventTypeResponse {
GetRelatingEventsWithRelTypeAndEventTypeResponse({
required this.chunk,
this.nextBatch,
this.prevBatch,
this.recursionDepth,
});
GetRelatingEventsWithRelTypeAndEventTypeResponse.fromJson(
Map<String, Object?> json)
: chunk = (json['chunk'] as List)
.map((v) => MatrixEvent.fromJson(v as Map<String, Object?>))
.toList(),
nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']),
prevBatch = ((v) => v != null ? v as String : null)(json['prev_batch']),
recursionDepth =
((v) => v != null ? v as int : null)(json['recursion_depth']);
Map<String, Object?> toJson() {
final nextBatch = this.nextBatch;
final prevBatch = this.prevBatch;
final recursionDepth = this.recursionDepth;
return {
'chunk': chunk.map((v) => v.toJson()).toList(),
if (nextBatch != null) 'next_batch': nextBatch,
if (prevBatch != null) 'prev_batch': prevBatch,
if (recursionDepth != null) 'recursion_depth': recursionDepth,
};
}
/// The child events of the requested event, ordered topologically most-recent
/// first. The events returned will match the `relType` and `eventType` supplied
/// in the URL.
List<MatrixEvent> chunk;
/// An opaque string representing a pagination token. The absence of this token
/// means there are no more results to fetch and the client should stop paginating.
String? nextBatch;
/// An opaque string representing a pagination token. The absence of this token
/// means this is the start of the result set, i.e. this is the first batch/page.
String? prevBatch;
/// If the `recurse` parameter was supplied by the client, this response field is
/// mandatory and gives the actual depth to which the server recursed. If the client
/// did not specify the `recurse` parameter, this field must be absent.
int? recursionDepth;
} }
/// ///
@ -492,8 +713,8 @@ class GetThreadRootsResponse {
}; };
} }
/// The thread roots, ordered by the `latest_event` in each event's aggregation bundle. All events /// The thread roots, ordered by the `latest_event` in each event's aggregated children. All events
/// returned include bundled [aggregations](https://spec.matrix.org/unstable/client-server-api/#aggregations). /// returned include bundled [aggregations](https://spec.matrix.org/unstable/client-server-api/#aggregations-of-child-events).
/// ///
/// If the thread root event was sent by an [ignored user](https://spec.matrix.org/unstable/client-server-api/#ignoring-users), the /// If the thread root event was sent by an [ignored user](https://spec.matrix.org/unstable/client-server-api/#ignoring-users), the
/// event is returned redacted to the caller. This is to simulate the same behaviour of a client doing /// event is returned redacted to the caller. This is to simulate the same behaviour of a client doing
@ -564,13 +785,13 @@ class ThirdPartyIdentifier {
'validated_at': validatedAt, 'validated_at': validatedAt,
}; };
/// The timestamp, in milliseconds, when the homeserver associated the third party identifier with the user. /// The timestamp, in milliseconds, when the homeserver associated the third-party identifier with the user.
int addedAt; int addedAt;
/// The third party identifier address. /// The third-party identifier address.
String address; String address;
/// The medium of the third party identifier. /// The medium of the third-party identifier.
ThirdPartyIdentifierMedium medium; ThirdPartyIdentifierMedium medium;
/// The timestamp, in milliseconds, when the identifier was /// The timestamp, in milliseconds, when the identifier was
@ -961,7 +1182,7 @@ class Invite3pid {
'medium': medium, 'medium': medium,
}; };
/// The invitee's third party identifier. /// The invitee's third-party identifier.
String address; String address;
/// An access token previously registered with the identity server. Servers /// An access token previously registered with the identity server. Servers
@ -969,7 +1190,7 @@ class Invite3pid {
/// and this specification version. /// and this specification version.
String idAccessToken; String idAccessToken;
/// The hostname+port of the identity server which should be used for third party identifier lookups. /// The hostname+port of the identity server which should be used for third-party identifier lookups.
String idServer; String idServer;
/// The kind of address being passed in the address field, for example `email` /// The kind of address being passed in the address field, for example `email`
@ -1155,7 +1376,7 @@ class PeekEventsResponse {
} }
/// A signature of an `m.third_party_invite` token to prove that this user /// A signature of an `m.third_party_invite` token to prove that this user
/// owns a third party identity which has been invited to the room. /// owns a third-party identity which has been invited to the room.
@_NameSource('spec') @_NameSource('spec')
class ThirdPartySigned { class ThirdPartySigned {
ThirdPartySigned({ ThirdPartySigned({
@ -1374,33 +1595,33 @@ class QueryKeysResponse {
@_NameSource('spec') @_NameSource('spec')
class LoginFlow { class LoginFlow {
LoginFlow({ LoginFlow({
this.type, this.getLoginToken,
required this.type,
}); });
LoginFlow.fromJson(Map<String, Object?> json) LoginFlow.fromJson(Map<String, Object?> json)
: type = ((v) => v != null ? v as String : null)(json['type']); : getLoginToken =
((v) => v != null ? v as bool : null)(json['get_login_token']),
type = json['type'] as String;
Map<String, Object?> toJson() { Map<String, Object?> toJson() {
final type = this.type; final getLoginToken = this.getLoginToken;
return { return {
if (type != null) 'type': type, if (getLoginToken != null) 'get_login_token': getLoginToken,
'type': type,
}; };
} }
/// If `type` is `m.login.token`, an optional field to indicate
/// to the unauthenticated client that the homeserver supports
/// the [`POST /login/get_token`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientv1loginget_token)
/// endpoint. Note that supporting the endpoint does not
/// necessarily indicate that the user attempting to log in will
/// be able to generate such a token.
bool? getLoginToken;
/// The login type. This is supplied as the `type` when /// The login type. This is supplied as the `type` when
/// logging in. /// logging in.
String? type; String type;
}
///
@_NameSource('rule override generated')
@EnhancedEnum()
enum LoginType {
@EnhancedEnumValue(name: 'm.login.password')
mLoginPassword,
@EnhancedEnumValue(name: 'm.login.token')
mLoginToken,
@EnhancedEnumValue(name: 'org.matrix.login.jwt')
mLoginJWT
} }
/// ///
@ -1713,7 +1934,9 @@ class PublicRoomQueryFilter {
: genericSearchTerm = ((v) => : genericSearchTerm = ((v) =>
v != null ? v as String : null)(json['generic_search_term']), v != null ? v as String : null)(json['generic_search_term']),
roomTypes = ((v) => v != null roomTypes = ((v) => v != null
? (v as List).map((v) => v as String).toList() ? (v as List)
.map((v) => ((v) => v != null ? v as String : null)(v))
.toList()
: null)(json['room_types']); : null)(json['room_types']);
Map<String, Object?> toJson() { Map<String, Object?> toJson() {
final genericSearchTerm = this.genericSearchTerm; final genericSearchTerm = this.genericSearchTerm;
@ -1732,7 +1955,7 @@ class PublicRoomQueryFilter {
/// for. To include rooms without a room type, specify `null` within this /// for. To include rooms without a room type, specify `null` within this
/// list. When not specified, all applicable rooms (regardless of type) /// list. When not specified, all applicable rooms (regardless of type)
/// are returned. /// are returned.
List<String>? roomTypes; List<String?>? roomTypes;
} }
/// A list of the rooms on the server. /// A list of the rooms on the server.
@ -1929,22 +2152,26 @@ class PushCondition {
this.key, this.key,
required this.kind, required this.kind,
this.pattern, this.pattern,
this.value,
}); });
PushCondition.fromJson(Map<String, Object?> json) PushCondition.fromJson(Map<String, Object?> json)
: is$ = ((v) => v != null ? v as String : null)(json['is']), : is$ = ((v) => v != null ? v as String : null)(json['is']),
key = ((v) => v != null ? v as String : null)(json['key']), key = ((v) => v != null ? v as String : null)(json['key']),
kind = json['kind'] as String, kind = json['kind'] as String,
pattern = ((v) => v != null ? v as String : null)(json['pattern']); pattern = ((v) => v != null ? v as String : null)(json['pattern']),
value = ((v) => v != null ? v as Object? : null)(json['value']);
Map<String, Object?> toJson() { Map<String, Object?> toJson() {
final is$ = this.is$; final is$ = this.is$;
final key = this.key; final key = this.key;
final pattern = this.pattern; final pattern = this.pattern;
final value = this.value;
return { return {
if (is$ != null) 'is': is$, if (is$ != null) 'is': is$,
if (key != null) 'key': key, if (key != null) 'key': key,
'kind': kind, 'kind': kind,
if (pattern != null) 'pattern': pattern, if (pattern != null) 'pattern': pattern,
if (value != null) 'value': value,
}; };
} }
@ -1954,8 +2181,8 @@ class PushCondition {
/// so forth. If no prefix is present, this parameter defaults to ==. /// so forth. If no prefix is present, this parameter defaults to ==.
String? is$; String? is$;
/// Required for `event_match` conditions. The dot-separated field of the /// Required for `event_match`, `event_property_is` and `event_property_contains`
/// event to match. /// conditions. The dot-separated field of the event to match.
/// ///
/// Required for `sender_notification_permission` conditions. The field in /// Required for `sender_notification_permission` conditions. The field in
/// the power level event the user needs a minimum power level for. Fields /// the power level event the user needs a minimum power level for. Fields
@ -1963,13 +2190,18 @@ class PushCondition {
/// event's `content`. /// event's `content`.
String? key; String? key;
/// The kind of condition to apply. See [conditions](https://spec.matrix.org/unstable/client-server-api/#conditions) for /// The kind of condition to apply. See [conditions](https://spec.matrix.org/unstable/client-server-api/#conditions-1) for
/// more information on the allowed kinds and how they work. /// more information on the allowed kinds and how they work.
String kind; String kind;
/// Required for `event_match` conditions. The glob-style pattern to /// Required for `event_match` conditions. The [glob-style pattern](https://spec.matrix.org/unstable/appendices#glob-style-matching)
/// match against. /// to match against.
String? pattern; String? pattern;
/// Required for `event_property_is` and `event_property_contains` conditions.
/// A non-compound [canonical JSON](https://spec.matrix.org/unstable/appendices#canonical-json) value to match
/// against.
Object? value;
} }
/// ///
@ -2023,8 +2255,8 @@ class PushRule {
/// Whether the push rule is enabled or not. /// Whether the push rule is enabled or not.
bool enabled; bool enabled;
/// The glob-style pattern to match against. Only applicable to `content` /// The [glob-style pattern](https://spec.matrix.org/unstable/appendices#glob-style-matching) to match against.
/// rules. /// Only applicable to `content` rules.
String? pattern; String? pattern;
/// The ID of this rule. /// The ID of this rule.
@ -2542,7 +2774,7 @@ class RoomMember {
}; };
} }
/// The mxc avatar url of the user this object is representing. /// The avatar of the user this object is representing, as an [`mxc://` URI](https://spec.matrix.org/unstable/client-server-api/#matrix-content-mxc-uris).
Uri? avatarUrl; Uri? avatarUrl;
/// The display name of the user this object is representing. /// The display name of the user this object is representing.
@ -2724,7 +2956,11 @@ class EventFilter {
}; };
} }
/// The maximum number of events to return. /// The maximum number of events to return, must be an integer greater than 0.
///
/// Servers should apply a default value, and impose a maximum value to avoid
/// resource exhaustion.
///
int? limit; int? limit;
/// A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the `'senders'` filter. /// A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the `'senders'` filter.
@ -2887,7 +3123,11 @@ class SearchFilter implements EventFilter, RoomEventFilter {
}; };
} }
/// The maximum number of events to return. /// The maximum number of events to return, must be an integer greater than 0.
///
/// Servers should apply a default value, and impose a maximum value to avoid
/// resource exhaustion.
///
@override @override
int? limit; int? limit;
@ -3245,7 +3485,7 @@ class SearchResultsEventContext {
/// The historic profile information of the /// The historic profile information of the
/// users that sent the events returned. /// users that sent the events returned.
/// ///
/// The `string` key is the user ID for which /// The key is the user ID for which
/// the profile belongs to. /// the profile belongs to.
Map<String, UserProfile>? profileInfo; Map<String, UserProfile>? profileInfo;
@ -3374,7 +3614,7 @@ class ResultRoomEvents {
/// This is included if the request had the /// This is included if the request had the
/// `include_state` key set with a value of `true`. /// `include_state` key set with a value of `true`.
/// ///
/// The `string` key is the room ID for which the `State /// The key is the room ID for which the `State
/// Event` array belongs to. /// Event` array belongs to.
Map<String, List<MatrixEvent>>? state; Map<String, List<MatrixEvent>>? state;
} }
@ -3441,10 +3681,10 @@ class Location {
/// An alias for a matrix room. /// An alias for a matrix room.
String alias; String alias;
/// Information used to identify this third party location. /// Information used to identify this third-party location.
Map<String, Object?> fields; Map<String, Object?> fields;
/// The protocol ID that the third party location is a part of. /// The protocol ID that the third-party location is a part of.
String protocol; String protocol;
} }
@ -3549,7 +3789,7 @@ class Protocol {
/// May be an empty object if no fields are defined. /// May be an empty object if no fields are defined.
Map<String, FieldType> fieldTypes; Map<String, FieldType> fieldTypes;
/// A content URI representing an icon for the third party protocol. /// A content URI representing an icon for the third-party protocol.
String icon; String icon;
/// A list of objects representing independent instances of configuration. /// A list of objects representing independent instances of configuration.
@ -3557,13 +3797,13 @@ class Protocol {
/// same application service. /// same application service.
List<ProtocolInstance> instances; List<ProtocolInstance> instances;
/// Fields which may be used to identify a third party location. These should be /// Fields which may be used to identify a third-party location. These should be
/// ordered to suggest the way that entities may be grouped, where higher /// ordered to suggest the way that entities may be grouped, where higher
/// groupings are ordered first. For example, the name of a network should be /// groupings are ordered first. For example, the name of a network should be
/// searched before the name of a channel. /// searched before the name of a channel.
List<String> locationFields; List<String> locationFields;
/// Fields which may be used to identify a third party user. These should be /// Fields which may be used to identify a third-party user. These should be
/// ordered to suggest the way that entities may be grouped, where higher /// ordered to suggest the way that entities may be grouped, where higher
/// groupings are ordered first. For example, the name of a network should be /// groupings are ordered first. For example, the name of a network should be
/// searched before the nickname of a user. /// searched before the nickname of a user.
@ -3589,13 +3829,13 @@ class ThirdPartyUser {
'userid': userid, 'userid': userid,
}; };
/// Information used to identify this third party location. /// Information used to identify this third-party location.
Map<String, Object?> fields; Map<String, Object?> fields;
/// The protocol ID that the third party location is a part of. /// The protocol ID that the third-party location is a part of.
String protocol; String protocol;
/// A Matrix User ID represting a third party user. /// A Matrix User ID represting a third-party user.
String userid; String userid;
} }
@ -3684,7 +3924,11 @@ class StateFilter implements EventFilter, RoomEventFilter {
}; };
} }
/// The maximum number of events to return. /// The maximum number of events to return, must be an integer greater than 0.
///
/// Servers should apply a default value, and impose a maximum value to avoid
/// resource exhaustion.
///
@override @override
int? limit; int? limit;
@ -3857,7 +4101,7 @@ class Filter {
/// The user account data that isn't associated with rooms to include. /// The user account data that isn't associated with rooms to include.
EventFilter? accountData; EventFilter? accountData;
/// List of event fields to include. If this list is absent then all fields are included. The entries may include '.' characters to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content' object. A literal '.' character in a field name may be escaped using a '\\'. A server may include more fields than were requested. /// List of event fields to include. If this list is absent then all fields are included. The entries are [dot-separated paths for each property](https://spec.matrix.org/unstable/appendices#dot-separated-property-paths) to include. So ['content.body'] will include the 'body' field of the 'content' object. A server may include more fields than were requested.
List<String>? eventFields; List<String>? eventFields;
/// The format to use for events. 'client' will return the events in a format suitable for clients. 'federation' will return the raw event as received over federation. The default is 'client'. /// The format to use for events. 'client' will return the events in a format suitable for clients. 'federation' will return the raw event as received over federation. The default is 'client'.
@ -3963,7 +4207,7 @@ class Profile {
}; };
} }
/// The avatar url, as an MXC, if one exists. /// The avatar url, as an [`mxc://` URI](https://spec.matrix.org/unstable/client-server-api/#matrix-content-mxc-uris), if one exists.
Uri? avatarUrl; Uri? avatarUrl;
/// The display name of the user, if one exists. /// The display name of the user, if one exists.
@ -4065,63 +4309,32 @@ class GetVersionsResponse {
} }
/// ///
@_NameSource('rule override generated') @_NameSource('generated')
class ServerConfig { class CreateContentResponse {
ServerConfig({ CreateContentResponse({
this.mUploadSize, required this.contentUri,
this.unusedExpiresAt,
}); });
ServerConfig.fromJson(Map<String, Object?> json) CreateContentResponse.fromJson(Map<String, Object?> json)
: mUploadSize = : contentUri = ((json['content_uri'] as String).startsWith('mxc://')
((v) => v != null ? v as int : null)(json['m.upload.size']); ? Uri.parse(json['content_uri'] as String)
: throw Exception('Uri not an mxc URI')),
unusedExpiresAt =
((v) => v != null ? v as int : null)(json['unused_expires_at']);
Map<String, Object?> toJson() { Map<String, Object?> toJson() {
final mUploadSize = this.mUploadSize; final unusedExpiresAt = this.unusedExpiresAt;
return { return {
if (mUploadSize != null) 'm.upload.size': mUploadSize, 'content_uri': contentUri.toString(),
if (unusedExpiresAt != null) 'unused_expires_at': unusedExpiresAt,
}; };
} }
/// The maximum size an upload can be in bytes. /// The [`mxc://` URI](https://spec.matrix.org/unstable/client-server-api/#matrix-content-mxc-uris) at
/// Clients SHOULD use this as a guide when uploading content. /// which the content will be available, once it is uploaded.
/// If not listed or null, the size limit should be treated as unknown. Uri contentUri;
int? mUploadSize;
} /// The timestamp (in milliseconds since the unix epoch) when the
/// generated media id will expire, if media is not uploaded.
/// int? unusedExpiresAt;
@_NameSource('generated')
class GetUrlPreviewResponse {
GetUrlPreviewResponse({
this.matrixImageSize,
this.ogImage,
});
GetUrlPreviewResponse.fromJson(Map<String, Object?> json)
: matrixImageSize =
((v) => v != null ? v as int : null)(json['matrix:image:size']),
ogImage = ((v) =>
v != null ? Uri.parse(v as String) : null)(json['og:image']);
Map<String, Object?> toJson() {
final matrixImageSize = this.matrixImageSize;
final ogImage = this.ogImage;
return {
if (matrixImageSize != null) 'matrix:image:size': matrixImageSize,
if (ogImage != null) 'og:image': ogImage.toString(),
};
}
/// The byte-size of the image. Omitted if there is no image attached.
int? matrixImageSize;
/// An [MXC URI](https://spec.matrix.org/unstable/client-server-api/#matrix-content-mxc-uris) to the image. Omitted if there is no image.
Uri? ogImage;
}
///
@_NameSource('generated')
@EnhancedEnum()
enum Method {
@EnhancedEnumValue(name: 'crop')
crop,
@EnhancedEnumValue(name: 'scale')
scale
} }

View File

@ -6,6 +6,88 @@ part of 'model.dart';
// EnhancedEnumGenerator // EnhancedEnumGenerator
// ************************************************************************** // **************************************************************************
extension RoleFromStringExtension on Iterable<Role> {
Role? fromString(String val) {
final override = {
'm.role.admin': Role.mRoleAdmin,
'm.role.security': Role.mRoleSecurity,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension RoleEnhancedEnum on Role {
@override
// ignore: override_on_non_overriding_member
String get name => {
Role.mRoleAdmin: 'm.role.admin',
Role.mRoleSecurity: 'm.role.security',
}[this]!;
bool get isMRoleAdmin => this == Role.mRoleAdmin;
bool get isMRoleSecurity => this == Role.mRoleSecurity;
T when<T>({
required T Function() mRoleAdmin,
required T Function() mRoleSecurity,
}) =>
{
Role.mRoleAdmin: mRoleAdmin,
Role.mRoleSecurity: mRoleSecurity,
}[this]!();
T maybeWhen<T>({
T? Function()? mRoleAdmin,
T? Function()? mRoleSecurity,
required T Function() orElse,
}) =>
{
Role.mRoleAdmin: mRoleAdmin,
Role.mRoleSecurity: mRoleSecurity,
}[this]
?.call() ??
orElse();
}
extension MethodFromStringExtension on Iterable<Method> {
Method? fromString(String val) {
final override = {
'crop': Method.crop,
'scale': Method.scale,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension MethodEnhancedEnum on Method {
@override
// ignore: override_on_non_overriding_member
String get name => {
Method.crop: 'crop',
Method.scale: 'scale',
}[this]!;
bool get isCrop => this == Method.crop;
bool get isScale => this == Method.scale;
T when<T>({
required T Function() crop,
required T Function() scale,
}) =>
{
Method.crop: crop,
Method.scale: scale,
}[this]!();
T maybeWhen<T>({
T? Function()? crop,
T? Function()? scale,
required T Function() orElse,
}) =>
{
Method.crop: crop,
Method.scale: scale,
}[this]
?.call() ??
orElse();
}
extension DirectionFromStringExtension on Iterable<Direction> { extension DirectionFromStringExtension on Iterable<Direction> {
Direction? fromString(String val) { Direction? fromString(String val) {
final override = { final override = {
@ -303,54 +385,6 @@ extension VisibilityEnhancedEnum on Visibility {
orElse(); orElse();
} }
extension LoginTypeFromStringExtension on Iterable<LoginType> {
LoginType? fromString(String val) {
final override = {
'm.login.password': LoginType.mLoginPassword,
'm.login.token': LoginType.mLoginToken,
'org.matrix.login.jwt': LoginType.mLoginJWT,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension LoginTypeEnhancedEnum on LoginType {
@override
// ignore: override_on_non_overriding_member
String get name => {
LoginType.mLoginPassword: 'm.login.password',
LoginType.mLoginToken: 'm.login.token',
LoginType.mLoginJWT: 'org.matrix.login.jwt',
}[this]!;
bool get isMLoginPassword => this == LoginType.mLoginPassword;
bool get isMLoginToken => this == LoginType.mLoginToken;
bool get isMLoginJWT => this == LoginType.mLoginJWT;
T when<T>({
required T Function() mLoginPassword,
required T Function() mLoginToken,
required T Function() mLoginJWT,
}) =>
{
LoginType.mLoginPassword: mLoginPassword,
LoginType.mLoginToken: mLoginToken,
LoginType.mLoginJWT: mLoginJWT,
}[this]!();
T maybeWhen<T>({
T? Function()? mLoginPassword,
T? Function()? mLoginToken,
T? Function()? mLoginJWT,
required T Function() orElse,
}) =>
{
LoginType.mLoginPassword: mLoginPassword,
LoginType.mLoginToken: mLoginToken,
LoginType.mLoginJWT: mLoginJWT,
}[this]
?.call() ??
orElse();
}
extension PresenceTypeFromStringExtension on Iterable<PresenceType> { extension PresenceTypeFromStringExtension on Iterable<PresenceType> {
PresenceType? fromString(String val) { PresenceType? fromString(String val) {
final override = { final override = {
@ -821,44 +855,3 @@ extension EventFormatEnhancedEnum on EventFormat {
?.call() ?? ?.call() ??
orElse(); orElse();
} }
extension MethodFromStringExtension on Iterable<Method> {
Method? fromString(String val) {
final override = {
'crop': Method.crop,
'scale': Method.scale,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension MethodEnhancedEnum on Method {
@override
// ignore: override_on_non_overriding_member
String get name => {
Method.crop: 'crop',
Method.scale: 'scale',
}[this]!;
bool get isCrop => this == Method.crop;
bool get isScale => this == Method.scale;
T when<T>({
required T Function() crop,
required T Function() scale,
}) =>
{
Method.crop: crop,
Method.scale: scale,
}[this]!();
T maybeWhen<T>({
T? Function()? crop,
T? Function()? scale,
required T Function() orElse,
}) =>
{
Method.crop: crop,
Method.scale: scale,
}[this]
?.call() ??
orElse();
}

View File

@ -150,27 +150,6 @@ class MatrixApi extends Api {
return jsonResp!; return jsonResp!;
} }
/// Publishes end-to-end encryption keys for the device.
/// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-keys-query
Future<Map<String, int>> uploadKeys(
{MatrixDeviceKeys? deviceKeys,
Map<String, Object?>? oneTimeKeys,
Map<String, Object?>? fallbackKeys}) async {
final response = await request(
RequestType.POST,
'/client/v3/keys/upload',
data: {
if (deviceKeys != null) 'device_keys': deviceKeys.toJson(),
if (oneTimeKeys != null) 'one_time_keys': oneTimeKeys,
if (fallbackKeys != null) ...{
'fallback_keys': fallbackKeys,
'org.matrix.msc2732.fallback_keys': fallbackKeys,
},
},
);
return Map<String, int>.from(response['one_time_key_counts'] as Map);
}
/// This endpoint allows the creation, modification and deletion of pushers /// This endpoint allows the creation, modification and deletion of pushers
/// for this user ID. The behaviour of this endpoint varies depending on the /// for this user ID. The behaviour of this endpoint varies depending on the
/// values in the JSON body. /// values in the JSON body.

View File

@ -12,7 +12,7 @@ extension UiaLogin on Client {
/// Set `pathVersion` to `r0` if you need to use the previous /// Set `pathVersion` to `r0` if you need to use the previous
/// version of the login endpoint. /// version of the login endpoint.
Future<LoginResponse> uiaLogin( Future<LoginResponse> uiaLogin(
LoginType type, { String type, {
String? address, String? address,
String? deviceId, String? deviceId,
AuthenticationIdentifier? identifier, AuthenticationIdentifier? identifier,
@ -37,10 +37,7 @@ extension UiaLogin on Client {
if (medium != null) 'medium': medium, if (medium != null) 'medium': medium,
if (password != null) 'password': password, if (password != null) 'password': password,
if (token != null) 'token': token, if (token != null) 'token': token,
'type': { 'type': type,
LoginType.mLoginPassword: 'm.login.password',
LoginType.mLoginToken: 'm.login.token'
}[type]!,
if (user != null) 'user': user, if (user != null) 'user': user,
if (auth != null) 'auth': auth.toJson(), if (auth != null) 'auth': auth.toJson(),
if (refreshToken != null) 'refresh_token': refreshToken, if (refreshToken != null) 'refresh_token': refreshToken,

View File

@ -538,7 +538,7 @@ class Client extends MatrixApi {
final loginTypes = await getLoginFlows() ?? []; final loginTypes = await getLoginFlows() ?? [];
if (!loginTypes.any((f) => supportedLoginTypes.contains(f.type))) { if (!loginTypes.any((f) => supportedLoginTypes.contains(f.type))) {
throw BadServerLoginTypesException( throw BadServerLoginTypesException(
loginTypes.map((f) => f.type ?? '').toSet(), supportedLoginTypes); loginTypes.map((f) => f.type).toSet(), supportedLoginTypes);
} }
return (wellKnown, versions, loginTypes); return (wellKnown, versions, loginTypes);
@ -628,7 +628,7 @@ class Client extends MatrixApi {
/// older server versions. /// older server versions.
@override @override
Future<LoginResponse> login( Future<LoginResponse> login(
LoginType type, { String type, {
AuthenticationIdentifier? identifier, AuthenticationIdentifier? identifier,
String? password, String? password,
String? token, String? token,
@ -1219,7 +1219,7 @@ class Client extends MatrixApi {
versionsResponse.unstableFeatures?['org.matrix.msc3916.stable'] == true; versionsResponse.unstableFeatures?['org.matrix.msc3916.stable'] == true;
} }
final _serverConfigCache = AsyncCache<ServerConfig>(const Duration(hours: 1)); final _serverConfigCache = AsyncCache<MediaConfig>(const Duration(hours: 1));
/// This endpoint allows clients to retrieve the configuration of the content /// This endpoint allows clients to retrieve the configuration of the content
/// repository, such as upload limitations. /// repository, such as upload limitations.
@ -1232,27 +1232,11 @@ class Client extends MatrixApi {
/// repository APIs, for example, proxies may enforce a lower upload size limit /// repository APIs, for example, proxies may enforce a lower upload size limit
/// than is advertised by the server on this endpoint. /// than is advertised by the server on this endpoint.
@override @override
Future<ServerConfig> getConfig() => Future<MediaConfig> getConfig() =>
_serverConfigCache.fetch(() => _getAuthenticatedConfig()); _serverConfigCache.fetch(() async => (await authenticatedMediaSupported())
? getConfigAuthed()
// TODO: remove once we are able to autogen this // ignore: deprecated_member_use_from_same_package
Future<ServerConfig> _getAuthenticatedConfig() async { : super.getConfig());
String path;
if (await authenticatedMediaSupported()) {
path = '_matrix/client/v1/media/config';
} else {
path = '_matrix/media/v3/config';
}
final requestUri = Uri(path: path);
final request = http.Request('GET', baseUri!.resolveUri(requestUri));
request.headers['authorization'] = 'Bearer ${bearerToken!}';
final response = await httpClient.send(request);
final responseBody = await response.stream.toBytes();
if (response.statusCode != 200) unexpectedResponse(response, responseBody);
final responseString = utf8.decode(responseBody);
final json = jsonDecode(responseString);
return ServerConfig.fromJson(json as Map<String, Object?>);
}
/// ///
/// ///
@ -1262,124 +1246,126 @@ class Client extends MatrixApi {
/// [mediaId] The media ID from the `mxc://` URI (the path component) /// [mediaId] The media ID from the `mxc://` URI (the path component)
/// ///
/// ///
/// [allowRemote] Indicates to the server that it should not attempt to fetch the media if it is deemed /// [allowRemote] Indicates to the server that it should not attempt to fetch the media if
/// remote. This is to prevent routing loops where the server contacts itself. Defaults to /// it is deemed remote. This is to prevent routing loops where the server
/// true if not provided. /// contacts itself.
///
/// Defaults to `true` if not provided.
///
/// [timeoutMs] The maximum number of milliseconds that the client is willing to wait to
/// start receiving data, in the case that the content has not yet been
/// uploaded. The default value is 20000 (20 seconds). The content
/// repository SHOULD impose a maximum value for this parameter. The
/// content repository MAY respond before the timeout.
///
///
/// [allowRedirect] Indicates to the server that it may return a 307 or 308 redirect
/// response that points at the relevant media content. When not explicitly
/// set to `true` the server must return the media content itself.
/// ///
@override @override
// TODO: remove once we are able to autogen this Future<FileResponse> getContent(
Future<FileResponse> getContent(String serverName, String mediaId, String serverName,
{bool? allowRemote}) async { String mediaId, {
String path; bool? allowRemote,
int? timeoutMs,
if (await authenticatedMediaSupported()) { bool? allowRedirect,
path = }) async {
'_matrix/client/v1/media/download/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}'; return (await authenticatedMediaSupported())
} else { ? getContentAuthed(
path = serverName,
'_matrix/media/v3/download/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}'; mediaId,
} timeoutMs: timeoutMs,
final requestUri = Uri(path: path, queryParameters: { )
if (allowRemote != null && !await authenticatedMediaSupported()) // ignore: deprecated_member_use_from_same_package
// removed with msc3916, so just to be explicit : super.getContent(
'allow_remote': allowRemote.toString(), serverName,
}); mediaId,
final request = http.Request('GET', baseUri!.resolveUri(requestUri)); allowRemote: allowRemote,
request.headers['authorization'] = 'Bearer ${bearerToken!}'; timeoutMs: timeoutMs,
final response = await httpClient.send(request); allowRedirect: allowRedirect,
final responseBody = await response.stream.toBytes(); );
if (response.statusCode != 200) unexpectedResponse(response, responseBody);
return FileResponse(
contentType: response.headers['content-type'], data: responseBody);
} }
/// This will download content from the content repository (same as /// This will download content from the content repository (same as
/// the previous endpoint) but replace the target file name with the one /// the previous endpoint) but replace the target file name with the one
/// provided by the caller. /// provided by the caller.
/// ///
/// [serverName] The server name from the `mxc://` URI (the authoritory component) /// {{% boxes/warning %}}
/// {{< changed-in v="1.11" >}} This endpoint MAY return `404 M_NOT_FOUND`
/// for media which exists, but is after the server froze unauthenticated
/// media access. See [Client Behaviour](https://spec.matrix.org/unstable/client-server-api/#content-repo-client-behaviour) for more
/// information.
/// {{% /boxes/warning %}}
///
/// [serverName] The server name from the `mxc://` URI (the authority component).
/// ///
/// ///
/// [mediaId] The media ID from the `mxc://` URI (the path component) /// [mediaId] The media ID from the `mxc://` URI (the path component).
/// ///
/// ///
/// [fileName] A filename to give in the `Content-Disposition` header. /// [fileName] A filename to give in the `Content-Disposition` header.
/// ///
/// [allowRemote] Indicates to the server that it should not attempt to fetch the media if it is deemed /// [allowRemote] Indicates to the server that it should not attempt to fetch the media if
/// remote. This is to prevent routing loops where the server contacts itself. Defaults to /// it is deemed remote. This is to prevent routing loops where the server
/// true if not provided. /// contacts itself.
/// ///
/// Defaults to `true` if not provided.
///
/// [timeoutMs] The maximum number of milliseconds that the client is willing to wait to
/// start receiving data, in the case that the content has not yet been
/// uploaded. The default value is 20000 (20 seconds). The content
/// repository SHOULD impose a maximum value for this parameter. The
/// content repository MAY respond before the timeout.
///
///
/// [allowRedirect] Indicates to the server that it may return a 307 or 308 redirect
/// response that points at the relevant media content. When not explicitly
/// set to `true` the server must return the media content itself.
@override @override
// TODO: remove once we are able to autogen this
Future<FileResponse> getContentOverrideName( Future<FileResponse> getContentOverrideName(
String serverName, String mediaId, String fileName, String serverName,
{bool? allowRemote}) async { String mediaId,
String path; String fileName, {
if (await authenticatedMediaSupported()) { bool? allowRemote,
path = int? timeoutMs,
'_matrix/client/v1/media/download/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}/${Uri.encodeComponent(fileName)}'; bool? allowRedirect,
} else { }) async {
path = return (await authenticatedMediaSupported())
'_matrix/media/v3/download/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}/${Uri.encodeComponent(fileName)}'; ? getContentOverrideNameAuthed(
} serverName,
final requestUri = Uri(path: path, queryParameters: { mediaId,
if (allowRemote != null && !await authenticatedMediaSupported()) fileName,
// removed with msc3916, so just to be explicit timeoutMs: timeoutMs,
'allow_remote': allowRemote.toString(), )
}); // ignore: deprecated_member_use_from_same_package
final request = http.Request('GET', baseUri!.resolveUri(requestUri)); : super.getContentOverrideName(
request.headers['authorization'] = 'Bearer ${bearerToken!}'; serverName,
final response = await httpClient.send(request); mediaId,
final responseBody = await response.stream.toBytes(); fileName,
if (response.statusCode != 200) unexpectedResponse(response, responseBody); allowRemote: allowRemote,
return FileResponse( timeoutMs: timeoutMs,
contentType: response.headers['content-type'], data: responseBody); allowRedirect: allowRedirect,
} );
/// Get information about a URL for the client. Typically this is called when a
/// client sees a URL in a message and wants to render a preview for the user.
///
/// **Note:**
/// Clients should consider avoiding this endpoint for URLs posted in encrypted
/// rooms. Encrypted rooms often contain more sensitive information the users
/// do not want to share with the homeserver, and this can mean that the URLs
/// being shared should also not be shared with the homeserver.
///
/// [url] The URL to get a preview of.
///
/// [ts] The preferred point in time to return a preview for. The server may
/// return a newer version if it does not have the requested version
/// available.
@override
// TODO: remove once we are able to autogen this
Future<GetUrlPreviewResponse> getUrlPreview(Uri url, {int? ts}) async {
String path;
if (await authenticatedMediaSupported()) {
path = '_matrix/client/v1/media/preview_url';
} else {
path = '_matrix/media/v3/preview_url';
}
final requestUri = Uri(path: path, queryParameters: {
'url': url.toString(),
if (ts != null) 'ts': ts.toString(),
});
final request = http.Request('GET', baseUri!.resolveUri(requestUri));
request.headers['authorization'] = 'Bearer ${bearerToken!}';
final response = await httpClient.send(request);
final responseBody = await response.stream.toBytes();
if (response.statusCode != 200) unexpectedResponse(response, responseBody);
final responseString = utf8.decode(responseBody);
final json = jsonDecode(responseString);
return GetUrlPreviewResponse.fromJson(json as Map<String, Object?>);
} }
/// Download a thumbnail of content from the content repository. /// Download a thumbnail of content from the content repository.
/// See the [Thumbnails](https://spec.matrix.org/unstable/client-server-api/#thumbnails) section for more information. /// See the [Thumbnails](https://spec.matrix.org/unstable/client-server-api/#thumbnails) section for more information.
/// ///
/// [serverName] The server name from the `mxc://` URI (the authoritory component) /// {{% boxes/note %}}
/// Clients SHOULD NOT generate or use URLs which supply the access token in
/// the query string. These URLs may be copied by users verbatim and provided
/// in a chat message to another user, disclosing the sender's access token.
/// {{% /boxes/note %}}
///
/// Clients MAY be redirected using the 307/308 responses below to download
/// the request object. This is typical when the homeserver uses a Content
/// Delivery Network (CDN).
///
/// [serverName] The server name from the `mxc://` URI (the authority component).
/// ///
/// ///
/// [mediaId] The media ID from the `mxc://` URI (the path component) /// [mediaId] The media ID from the `mxc://` URI (the path component).
/// ///
/// ///
/// [width] The *desired* width of the thumbnail. The actual thumbnail may be /// [width] The *desired* width of the thumbnail. The actual thumbnail may be
@ -1391,39 +1377,82 @@ class Client extends MatrixApi {
/// [method] The desired resizing method. See the [Thumbnails](https://spec.matrix.org/unstable/client-server-api/#thumbnails) /// [method] The desired resizing method. See the [Thumbnails](https://spec.matrix.org/unstable/client-server-api/#thumbnails)
/// section for more information. /// section for more information.
/// ///
/// [allowRemote] Indicates to the server that it should not attempt to fetch /// [timeoutMs] The maximum number of milliseconds that the client is willing to wait to
/// the media if it is deemed remote. This is to prevent routing loops /// start receiving data, in the case that the content has not yet been
/// where the server contacts itself. Defaults to true if not provided. /// uploaded. The default value is 20000 (20 seconds). The content
/// repository SHOULD impose a maximum value for this parameter. The
/// content repository MAY respond before the timeout.
///
///
/// [animated] Indicates preference for an animated thumbnail from the server, if possible. Animated
/// thumbnails typically use the content types `image/gif`, `image/png` (with APNG format),
/// `image/apng`, and `image/webp` instead of the common static `image/png` or `image/jpeg`
/// content types.
///
/// When `true`, the server SHOULD return an animated thumbnail if possible and supported.
/// When `false`, the server MUST NOT return an animated thumbnail. For example, returning a
/// static `image/png` or `image/jpeg` thumbnail. When not provided, the server SHOULD NOT
/// return an animated thumbnail.
///
/// Servers SHOULD prefer to return `image/webp` thumbnails when supporting animation.
///
/// When `true` and the media cannot be animated, such as in the case of a JPEG or PDF, the
/// server SHOULD behave as though `animated` is `false`.
@override @override
// TODO: remove once we are able to autogen this
Future<FileResponse> getContentThumbnail( Future<FileResponse> getContentThumbnail(
String serverName, String mediaId, int width, int height, String serverName,
{Method? method, bool? allowRemote}) async { String mediaId,
String path; int width,
if (await authenticatedMediaSupported()) { int height, {
path = Method? method,
'_matrix/client/v1/media/thumbnail/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}'; bool? allowRemote,
} else { int? timeoutMs,
path = bool? allowRedirect,
'_matrix/media/v3/thumbnail/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}'; bool? animated,
} }) async {
return (await authenticatedMediaSupported())
? getContentThumbnailAuthed(
serverName,
mediaId,
width,
height,
method: method,
timeoutMs: timeoutMs,
animated: animated,
)
// ignore: deprecated_member_use_from_same_package
: super.getContentThumbnail(
serverName,
mediaId,
width,
height,
method: method,
timeoutMs: timeoutMs,
animated: animated,
);
}
final requestUri = Uri(path: path, queryParameters: { /// Get information about a URL for the client. Typically this is called when a
'width': width.toString(), /// client sees a URL in a message and wants to render a preview for the user.
'height': height.toString(), ///
if (method != null) 'method': method.name, /// {{% boxes/note %}}
if (allowRemote != null && !await authenticatedMediaSupported()) /// Clients should consider avoiding this endpoint for URLs posted in encrypted
// removed with msc3916, so just to be explicit /// rooms. Encrypted rooms often contain more sensitive information the users
'allow_remote': allowRemote.toString(), /// do not want to share with the homeserver, and this can mean that the URLs
}); /// being shared should also not be shared with the homeserver.
/// {{% /boxes/note %}}
final request = http.Request('GET', baseUri!.resolveUri(requestUri)); ///
request.headers['authorization'] = 'Bearer ${bearerToken!}'; /// [url] The URL to get a preview of.
final response = await httpClient.send(request); ///
final responseBody = await response.stream.toBytes(); /// [ts] The preferred point in time to return a preview for. The server may
if (response.statusCode != 200) unexpectedResponse(response, responseBody); /// return a newer version if it does not have the requested version
return FileResponse( /// available.
contentType: response.headers['content-type'], data: responseBody); @override
Future<PreviewForUrl> getUrlPreview(Uri url, {int? ts}) async {
return (await authenticatedMediaSupported())
? getUrlPreviewAuthed(url, ts: ts)
// ignore: deprecated_member_use_from_same_package
: super.getUrlPreview(url, ts: ts);
} }
/// Uploads a file and automatically caches it in the database, if it is small enough /// Uploads a file and automatically caches it in the database, if it is small enough
@ -1614,7 +1643,7 @@ class Client extends MatrixApi {
final CachedStreamController<KeyVerification> onKeyVerificationRequest = final CachedStreamController<KeyVerification> onKeyVerificationRequest =
CachedStreamController(); CachedStreamController();
/// When the library calls an endpoint that needs UIA the `UiaRequest` is passed down this screen. /// When the library calls an endpoint that needs UIA the `UiaRequest` is passed down this stream.
/// The client can open a UIA prompt based on this. /// The client can open a UIA prompt based on this.
final CachedStreamController<UiaRequest> onUiaRequest = final CachedStreamController<UiaRequest> onUiaRequest =
CachedStreamController(); CachedStreamController();
@ -3348,10 +3377,12 @@ class Client extends MatrixApi {
/// Changes the password. You should either set oldPasswort or another authentication flow. /// Changes the password. You should either set oldPasswort or another authentication flow.
@override @override
Future<void> changePassword(String newPassword, Future<void> changePassword(
{String? oldPassword, String newPassword, {
AuthenticationData? auth, String? oldPassword,
bool? logoutDevices}) async { AuthenticationData? auth,
bool? logoutDevices,
}) async {
final userID = this.userID; final userID = this.userID;
try { try {
if (oldPassword != null && userID != null) { if (oldPassword != null && userID != null) {

View File

@ -0,0 +1,4 @@
abstract class LoginType {
static const mLoginPassword = 'm.login.password';
static const mLoginToken = 'm.login.token';
}

View File

@ -450,11 +450,12 @@ class Room {
/// Add a tag to the room. /// Add a tag to the room.
Future<void> addTag(String tag, {double? order}) => client.setRoomTag( Future<void> addTag(String tag, {double? order}) => client.setRoomTag(
client.userID!, client.userID!,
id, id,
tag, tag,
Tag(
order: order, order: order,
); ));
/// Removes a tag from the room. /// Removes a tag from the room.
Future<void> removeTag(String tag) => client.deleteRoomTag( Future<void> removeTag(String tag) => client.deleteRoomTag(
@ -469,8 +470,9 @@ class Room {
static Tag _tryTagFromJson(Object o) { static Tag _tryTagFromJson(Object o) {
if (o is Map<String, dynamic>) { if (o is Map<String, dynamic>) {
return Tag( return Tag(
order: o.tryGet<num>('order', TryGet.silent)?.toDouble(), order: o.tryGet<num>('order', TryGet.silent)?.toDouble(),
additionalProperties: Map.from(o)..remove('order')); additionalProperties: Map.from(o)..remove('order'),
);
} }
return Tag(); return Tag();
} }