async-matrix 3.0.0-arm-linux-musl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +200 -0
  3. data/README.md +108 -0
  4. data/data/discord-api-spec/openapi.json +40404 -0
  5. data/data/matrix-spec/api/client-server/account-data.yaml +389 -0
  6. data/data/matrix-spec/api/client-server/account_deactivation.yaml +149 -0
  7. data/data/matrix-spec/api/client-server/admin.yaml +512 -0
  8. data/data/matrix-spec/api/client-server/administrative_contact.yaml +620 -0
  9. data/data/matrix-spec/api/client-server/appservice_ping.yaml +183 -0
  10. data/data/matrix-spec/api/client-server/appservice_room_directory.yaml +104 -0
  11. data/data/matrix-spec/api/client-server/authed-content-repo.yaml +590 -0
  12. data/data/matrix-spec/api/client-server/banning.yaml +177 -0
  13. data/data/matrix-spec/api/client-server/capabilities.yaml +235 -0
  14. data/data/matrix-spec/api/client-server/content-repo.yaml +887 -0
  15. data/data/matrix-spec/api/client-server/create_room.yaml +306 -0
  16. data/data/matrix-spec/api/client-server/cross_signing.yaml +300 -0
  17. data/data/matrix-spec/api/client-server/definitions/auth_data.yaml +34 -0
  18. data/data/matrix-spec/api/client-server/definitions/auth_response.yaml +62 -0
  19. data/data/matrix-spec/api/client-server/definitions/client_device.yaml +44 -0
  20. data/data/matrix-spec/api/client-server/definitions/client_event.yaml +49 -0
  21. data/data/matrix-spec/api/client-server/definitions/client_event_without_room_id.yaml +147 -0
  22. data/data/matrix-spec/api/client-server/definitions/cross_signing_key.yaml +57 -0
  23. data/data/matrix-spec/api/client-server/definitions/device_keys.yaml +70 -0
  24. data/data/matrix-spec/api/client-server/definitions/errors/error.yaml +26 -0
  25. data/data/matrix-spec/api/client-server/definitions/errors/rate_limited.yaml +34 -0
  26. data/data/matrix-spec/api/client-server/definitions/event_batch.yaml +22 -0
  27. data/data/matrix-spec/api/client-server/definitions/event_filter.yaml +55 -0
  28. data/data/matrix-spec/api/client-server/definitions/invite_3pid.yaml +45 -0
  29. data/data/matrix-spec/api/client-server/definitions/key_backup_auth_data.yaml +36 -0
  30. data/data/matrix-spec/api/client-server/definitions/key_backup_data.yaml +50 -0
  31. data/data/matrix-spec/api/client-server/definitions/key_backup_session_data.yaml +57 -0
  32. data/data/matrix-spec/api/client-server/definitions/m.login.terms_params.yaml +83 -0
  33. data/data/matrix-spec/api/client-server/definitions/m.mentions.yaml +33 -0
  34. data/data/matrix-spec/api/client-server/definitions/m.oauth_params.yaml +30 -0
  35. data/data/matrix-spec/api/client-server/definitions/m.relates_to.yaml +45 -0
  36. data/data/matrix-spec/api/client-server/definitions/megolm_export_session_data.yaml +39 -0
  37. data/data/matrix-spec/api/client-server/definitions/olm_payload.yaml +88 -0
  38. data/data/matrix-spec/api/client-server/definitions/one_time_keys.yaml +27 -0
  39. data/data/matrix-spec/api/client-server/definitions/openid_token.yaml +37 -0
  40. data/data/matrix-spec/api/client-server/definitions/protocol.yaml +44 -0
  41. data/data/matrix-spec/api/client-server/definitions/public_rooms_chunk.yaml +74 -0
  42. data/data/matrix-spec/api/client-server/definitions/public_rooms_response.yaml +59 -0
  43. data/data/matrix-spec/api/client-server/definitions/push_condition.yaml +53 -0
  44. data/data/matrix-spec/api/client-server/definitions/push_rule.yaml +53 -0
  45. data/data/matrix-spec/api/client-server/definitions/push_ruleset.yaml +206 -0
  46. data/data/matrix-spec/api/client-server/definitions/recent_emoji.yaml +29 -0
  47. data/data/matrix-spec/api/client-server/definitions/request_email_validation.yaml +36 -0
  48. data/data/matrix-spec/api/client-server/definitions/request_msisdn_validation.yaml +36 -0
  49. data/data/matrix-spec/api/client-server/definitions/request_token_response.yaml +46 -0
  50. data/data/matrix-spec/api/client-server/definitions/room_event_filter.yaml +60 -0
  51. data/data/matrix-spec/api/client-server/definitions/room_key_backup.yaml +37 -0
  52. data/data/matrix-spec/api/client-server/definitions/room_summary.yaml +44 -0
  53. data/data/matrix-spec/api/client-server/definitions/security.yaml +47 -0
  54. data/data/matrix-spec/api/client-server/definitions/sso_login_flow.yaml +98 -0
  55. data/data/matrix-spec/api/client-server/definitions/state_event_batch.yaml +21 -0
  56. data/data/matrix-spec/api/client-server/definitions/sync_filter.yaml +86 -0
  57. data/data/matrix-spec/api/client-server/definitions/tag.yaml +24 -0
  58. data/data/matrix-spec/api/client-server/definitions/third_party_signed.yaml +45 -0
  59. data/data/matrix-spec/api/client-server/definitions/timeline_batch.yaml +36 -0
  60. data/data/matrix-spec/api/client-server/definitions/user_identifier.yaml +27 -0
  61. data/data/matrix-spec/api/client-server/definitions/wellknown/full.yaml +38 -0
  62. data/data/matrix-spec/api/client-server/definitions/wellknown/homeserver.yaml +25 -0
  63. data/data/matrix-spec/api/client-server/definitions/wellknown/identity_server.yaml +25 -0
  64. data/data/matrix-spec/api/client-server/device_management.yaml +314 -0
  65. data/data/matrix-spec/api/client-server/directory.yaml +318 -0
  66. data/data/matrix-spec/api/client-server/event_context.yaml +161 -0
  67. data/data/matrix-spec/api/client-server/filter.yaml +224 -0
  68. data/data/matrix-spec/api/client-server/inviting.yaml +149 -0
  69. data/data/matrix-spec/api/client-server/joining.yaml +238 -0
  70. data/data/matrix-spec/api/client-server/key_backup.yaml +993 -0
  71. data/data/matrix-spec/api/client-server/keys.yaml +482 -0
  72. data/data/matrix-spec/api/client-server/kicking.yaml +110 -0
  73. data/data/matrix-spec/api/client-server/knocking.yaml +152 -0
  74. data/data/matrix-spec/api/client-server/leaving.yaml +163 -0
  75. data/data/matrix-spec/api/client-server/list_joined_rooms.yaml +68 -0
  76. data/data/matrix-spec/api/client-server/list_public_rooms.yaml +280 -0
  77. data/data/matrix-spec/api/client-server/login.yaml +321 -0
  78. data/data/matrix-spec/api/client-server/login_token.yaml +138 -0
  79. data/data/matrix-spec/api/client-server/logout.yaml +86 -0
  80. data/data/matrix-spec/api/client-server/message_pagination.yaml +194 -0
  81. data/data/matrix-spec/api/client-server/notifications.yaml +152 -0
  82. data/data/matrix-spec/api/client-server/oauth_server_metadata.yaml +238 -0
  83. data/data/matrix-spec/api/client-server/old_sync.yaml +379 -0
  84. data/data/matrix-spec/api/client-server/openid.yaml +98 -0
  85. data/data/matrix-spec/api/client-server/password_management.yaml +246 -0
  86. data/data/matrix-spec/api/client-server/peeking_events.yaml +122 -0
  87. data/data/matrix-spec/api/client-server/policy_server.yaml +82 -0
  88. data/data/matrix-spec/api/client-server/presence.yaml +169 -0
  89. data/data/matrix-spec/api/client-server/profile.yaml +366 -0
  90. data/data/matrix-spec/api/client-server/pusher.yaml +303 -0
  91. data/data/matrix-spec/api/client-server/pushrules.yaml +633 -0
  92. data/data/matrix-spec/api/client-server/read_markers.yaml +103 -0
  93. data/data/matrix-spec/api/client-server/receipts.yaml +139 -0
  94. data/data/matrix-spec/api/client-server/redaction.yaml +116 -0
  95. data/data/matrix-spec/api/client-server/refresh.yaml +119 -0
  96. data/data/matrix-spec/api/client-server/registration.yaml +488 -0
  97. data/data/matrix-spec/api/client-server/registration_tokens.yaml +93 -0
  98. data/data/matrix-spec/api/client-server/relations.yaml +382 -0
  99. data/data/matrix-spec/api/client-server/report_content.yaml +283 -0
  100. data/data/matrix-spec/api/client-server/room_event_by_timestamp.yaml +147 -0
  101. data/data/matrix-spec/api/client-server/room_initial_sync.yaml +188 -0
  102. data/data/matrix-spec/api/client-server/room_send.yaml +130 -0
  103. data/data/matrix-spec/api/client-server/room_state.yaml +159 -0
  104. data/data/matrix-spec/api/client-server/room_summary.yaml +138 -0
  105. data/data/matrix-spec/api/client-server/room_upgrades.yaml +130 -0
  106. data/data/matrix-spec/api/client-server/rooms.yaml +380 -0
  107. data/data/matrix-spec/api/client-server/search.yaml +385 -0
  108. data/data/matrix-spec/api/client-server/space_hierarchy.yaml +237 -0
  109. data/data/matrix-spec/api/client-server/sso_login_redirect.yaml +135 -0
  110. data/data/matrix-spec/api/client-server/support.yaml +142 -0
  111. data/data/matrix-spec/api/client-server/sync.yaml +692 -0
  112. data/data/matrix-spec/api/client-server/tags.yaml +183 -0
  113. data/data/matrix-spec/api/client-server/third_party_lookup.yaml +324 -0
  114. data/data/matrix-spec/api/client-server/third_party_membership.yaml +139 -0
  115. data/data/matrix-spec/api/client-server/threads_list.yaml +167 -0
  116. data/data/matrix-spec/api/client-server/to_device.yaml +104 -0
  117. data/data/matrix-spec/api/client-server/typing.yaml +103 -0
  118. data/data/matrix-spec/api/client-server/users.yaml +136 -0
  119. data/data/matrix-spec/api/client-server/versions.yaml +108 -0
  120. data/data/matrix-spec/api/client-server/voip.yaml +93 -0
  121. data/data/matrix-spec/api/client-server/wellknown.yaml +60 -0
  122. data/data/matrix-spec/api/client-server/whoami.yaml +121 -0
  123. data/data/matrix-spec/event-schemas/examples/core/event.json +6 -0
  124. data/data/matrix-spec/event-schemas/examples/core/room_edu.json +3 -0
  125. data/data/matrix-spec/event-schemas/examples/core/room_event.json +11 -0
  126. data/data/matrix-spec/event-schemas/examples/core/state_event.json +4 -0
  127. data/data/matrix-spec/event-schemas/examples/invite_room_state.json +18 -0
  128. data/data/matrix-spec/event-schemas/examples/knock_room_state.json +18 -0
  129. data/data/matrix-spec/event-schemas/examples/m.accepted_terms.yaml +10 -0
  130. data/data/matrix-spec/event-schemas/examples/m.call.answer.yaml +21 -0
  131. data/data/matrix-spec/event-schemas/examples/m.call.candidates.yaml +16 -0
  132. data/data/matrix-spec/event-schemas/examples/m.call.hangup.yaml +10 -0
  133. data/data/matrix-spec/event-schemas/examples/m.call.invite.yaml +22 -0
  134. data/data/matrix-spec/event-schemas/examples/m.call.negotiate.yaml +22 -0
  135. data/data/matrix-spec/event-schemas/examples/m.call.reject.yaml +9 -0
  136. data/data/matrix-spec/event-schemas/examples/m.call.sdp_stream_metadata_changed.yaml +16 -0
  137. data/data/matrix-spec/event-schemas/examples/m.call.select_answer.yaml +10 -0
  138. data/data/matrix-spec/event-schemas/examples/m.direct.yaml +10 -0
  139. data/data/matrix-spec/event-schemas/examples/m.dummy.yaml +4 -0
  140. data/data/matrix-spec/event-schemas/examples/m.forwarded_room_key.yaml +14 -0
  141. data/data/matrix-spec/event-schemas/examples/m.fully_read.yaml +7 -0
  142. data/data/matrix-spec/event-schemas/examples/m.identity_server.yaml +7 -0
  143. data/data/matrix-spec/event-schemas/examples/m.ignored_user_list.yaml +9 -0
  144. data/data/matrix-spec/event-schemas/examples/m.invite_permission_config.yaml +7 -0
  145. data/data/matrix-spec/event-schemas/examples/m.key.verification.accept.yaml +12 -0
  146. data/data/matrix-spec/event-schemas/examples/m.key.verification.cancel.yaml +8 -0
  147. data/data/matrix-spec/event-schemas/examples/m.key.verification.done.yaml +6 -0
  148. data/data/matrix-spec/event-schemas/examples/m.key.verification.key.yaml +7 -0
  149. data/data/matrix-spec/event-schemas/examples/m.key.verification.mac.yaml +10 -0
  150. data/data/matrix-spec/event-schemas/examples/m.key.verification.ready.yaml +10 -0
  151. data/data/matrix-spec/event-schemas/examples/m.key.verification.request.yaml +11 -0
  152. data/data/matrix-spec/event-schemas/examples/m.key.verification.start$m.sas.v1.yaml +12 -0
  153. data/data/matrix-spec/event-schemas/examples/m.key.verification.start.yaml +8 -0
  154. data/data/matrix-spec/event-schemas/examples/m.key_backup.yaml +7 -0
  155. data/data/matrix-spec/event-schemas/examples/m.marked_unread.yaml +7 -0
  156. data/data/matrix-spec/event-schemas/examples/m.policy.rule.room.yaml +10 -0
  157. data/data/matrix-spec/event-schemas/examples/m.policy.rule.server.yaml +10 -0
  158. data/data/matrix-spec/event-schemas/examples/m.policy.rule.user.yaml +10 -0
  159. data/data/matrix-spec/event-schemas/examples/m.presence.yaml +12 -0
  160. data/data/matrix-spec/event-schemas/examples/m.push_rules.yaml +177 -0
  161. data/data/matrix-spec/event-schemas/examples/m.reaction.yaml +11 -0
  162. data/data/matrix-spec/event-schemas/examples/m.receipt.yaml +18 -0
  163. data/data/matrix-spec/event-schemas/examples/m.recent_emoji.yaml +16 -0
  164. data/data/matrix-spec/event-schemas/examples/m.room.avatar.yaml +14 -0
  165. data/data/matrix-spec/event-schemas/examples/m.room.canonical_alias.yaml +12 -0
  166. data/data/matrix-spec/event-schemas/examples/m.room.create.yaml +13 -0
  167. data/data/matrix-spec/event-schemas/examples/m.room.encrypted$megolm.yaml +11 -0
  168. data/data/matrix-spec/event-schemas/examples/m.room.encrypted$olm.yaml +14 -0
  169. data/data/matrix-spec/event-schemas/examples/m.room.encryption.yaml +10 -0
  170. data/data/matrix-spec/event-schemas/examples/m.room.guest_access.yaml +8 -0
  171. data/data/matrix-spec/event-schemas/examples/m.room.history_visibility.yaml +8 -0
  172. data/data/matrix-spec/event-schemas/examples/m.room.join_rules$restricted.yaml +18 -0
  173. data/data/matrix-spec/event-schemas/examples/m.room.join_rules.yaml +8 -0
  174. data/data/matrix-spec/event-schemas/examples/m.room.member$invite_room_state.yaml +15 -0
  175. data/data/matrix-spec/event-schemas/examples/m.room.member$join_authorised_via_users_server.yaml +12 -0
  176. data/data/matrix-spec/event-schemas/examples/m.room.member$knock_room_state.yaml +15 -0
  177. data/data/matrix-spec/event-schemas/examples/m.room.member$third_party_invite.yaml +20 -0
  178. data/data/matrix-spec/event-schemas/examples/m.room.member.yaml +12 -0
  179. data/data/matrix-spec/event-schemas/examples/m.room.message$m.audio.yaml +14 -0
  180. data/data/matrix-spec/event-schemas/examples/m.room.message$m.emote.yaml +10 -0
  181. data/data/matrix-spec/event-schemas/examples/m.room.message$m.file.yaml +14 -0
  182. data/data/matrix-spec/event-schemas/examples/m.room.message$m.image.yaml +16 -0
  183. data/data/matrix-spec/event-schemas/examples/m.room.message$m.key.verification.request.yaml +19 -0
  184. data/data/matrix-spec/event-schemas/examples/m.room.message$m.location.yaml +18 -0
  185. data/data/matrix-spec/event-schemas/examples/m.room.message$m.notice.yaml +10 -0
  186. data/data/matrix-spec/event-schemas/examples/m.room.message$m.server_notice.yaml +11 -0
  187. data/data/matrix-spec/event-schemas/examples/m.room.message$m.text.yaml +10 -0
  188. data/data/matrix-spec/event-schemas/examples/m.room.message$m.video.yaml +23 -0
  189. data/data/matrix-spec/event-schemas/examples/m.room.name.yaml +8 -0
  190. data/data/matrix-spec/event-schemas/examples/m.room.pinned_events.yaml +8 -0
  191. data/data/matrix-spec/event-schemas/examples/m.room.policy.yaml +11 -0
  192. data/data/matrix-spec/event-schemas/examples/m.room.power_levels.yaml +24 -0
  193. data/data/matrix-spec/event-schemas/examples/m.room.redaction.yaml +8 -0
  194. data/data/matrix-spec/event-schemas/examples/m.room.server_acl.yaml +10 -0
  195. data/data/matrix-spec/event-schemas/examples/m.room.third_party_invite.yaml +14 -0
  196. data/data/matrix-spec/event-schemas/examples/m.room.tombstone.yaml +9 -0
  197. data/data/matrix-spec/event-schemas/examples/m.room.topic.yaml +16 -0
  198. data/data/matrix-spec/event-schemas/examples/m.room_key.withheld.yaml +12 -0
  199. data/data/matrix-spec/event-schemas/examples/m.room_key.yaml +10 -0
  200. data/data/matrix-spec/event-schemas/examples/m.room_key_request$cancel_request.yaml +8 -0
  201. data/data/matrix-spec/event-schemas/examples/m.room_key_request$request.yaml +14 -0
  202. data/data/matrix-spec/event-schemas/examples/m.secret.request.yaml +9 -0
  203. data/data/matrix-spec/event-schemas/examples/m.secret.send.yaml +7 -0
  204. data/data/matrix-spec/event-schemas/examples/m.space.child.yaml +10 -0
  205. data/data/matrix-spec/event-schemas/examples/m.space.parent.yaml +9 -0
  206. data/data/matrix-spec/event-schemas/examples/m.sticker.yaml +22 -0
  207. data/data/matrix-spec/event-schemas/examples/m.tag.yaml +9 -0
  208. data/data/matrix-spec/event-schemas/examples/m.typing.yaml +7 -0
  209. data/data/matrix-spec/event-schemas/moderation_policy_rule.yaml +32 -0
  210. data/data/matrix-spec/event-schemas/schema/components/m_text_content_block.yaml +28 -0
  211. data/data/matrix-spec/event-schemas/schema/components/sdp_stream_metadata.yaml +43 -0
  212. data/data/matrix-spec/event-schemas/schema/components/signed_third_party_invite.yaml +48 -0
  213. data/data/matrix-spec/event-schemas/schema/core-event-schema/call_event.yaml +27 -0
  214. data/data/matrix-spec/event-schemas/schema/core-event-schema/event.yaml +16 -0
  215. data/data/matrix-spec/event-schemas/schema/core-event-schema/msgtype_infos/avatar_info.yaml +30 -0
  216. data/data/matrix-spec/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml +52 -0
  217. data/data/matrix-spec/event-schemas/schema/core-event-schema/msgtype_infos/thumbnail_info.yaml +22 -0
  218. data/data/matrix-spec/event-schemas/schema/core-event-schema/room_event.yaml +17 -0
  219. data/data/matrix-spec/event-schemas/schema/core-event-schema/state_event.yaml +8 -0
  220. data/data/matrix-spec/event-schemas/schema/core-event-schema/stripped_state.yaml +48 -0
  221. data/data/matrix-spec/event-schemas/schema/core-event-schema/sync_room_event.yaml +49 -0
  222. data/data/matrix-spec/event-schemas/schema/core-event-schema/sync_state_event.yaml +36 -0
  223. data/data/matrix-spec/event-schemas/schema/core-event-schema/unsigned_prop.yaml +23 -0
  224. data/data/matrix-spec/event-schemas/schema/m.accepted_terms.yaml +25 -0
  225. data/data/matrix-spec/event-schemas/schema/m.call.answer.yaml +44 -0
  226. data/data/matrix-spec/event-schemas/schema/m.call.candidates.yaml +52 -0
  227. data/data/matrix-spec/event-schemas/schema/m.call.hangup.yaml +57 -0
  228. data/data/matrix-spec/event-schemas/schema/m.call.invite.yaml +53 -0
  229. data/data/matrix-spec/event-schemas/schema/m.call.negotiate.yaml +78 -0
  230. data/data/matrix-spec/event-schemas/schema/m.call.reject.yaml +29 -0
  231. data/data/matrix-spec/event-schemas/schema/m.call.sdp_stream_metadata_changed.yaml +24 -0
  232. data/data/matrix-spec/event-schemas/schema/m.call.select_answer.yaml +29 -0
  233. data/data/matrix-spec/event-schemas/schema/m.direct.yaml +29 -0
  234. data/data/matrix-spec/event-schemas/schema/m.dummy.yaml +25 -0
  235. data/data/matrix-spec/event-schemas/schema/m.forwarded_room_key.yaml +70 -0
  236. data/data/matrix-spec/event-schemas/schema/m.fully_read.yaml +26 -0
  237. data/data/matrix-spec/event-schemas/schema/m.identity_server.yaml +28 -0
  238. data/data/matrix-spec/event-schemas/schema/m.ignored_user_list.yaml +30 -0
  239. data/data/matrix-spec/event-schemas/schema/m.invite_permission_config.yaml +21 -0
  240. data/data/matrix-spec/event-schemas/schema/m.key.verification.accept.yaml +63 -0
  241. data/data/matrix-spec/event-schemas/schema/m.key.verification.cancel.yaml +72 -0
  242. data/data/matrix-spec/event-schemas/schema/m.key.verification.done.yaml +24 -0
  243. data/data/matrix-spec/event-schemas/schema/m.key.verification.key.yaml +31 -0
  244. data/data/matrix-spec/event-schemas/schema/m.key.verification.m.relates_to.yaml +23 -0
  245. data/data/matrix-spec/event-schemas/schema/m.key.verification.mac.yaml +43 -0
  246. data/data/matrix-spec/event-schemas/schema/m.key.verification.ready.yaml +41 -0
  247. data/data/matrix-spec/event-schemas/schema/m.key.verification.request.yaml +47 -0
  248. data/data/matrix-spec/event-schemas/schema/m.key.verification.start$m.reciprocate.v1.yaml +45 -0
  249. data/data/matrix-spec/event-schemas/schema/m.key.verification.start$m.sas.v1.yaml +76 -0
  250. data/data/matrix-spec/event-schemas/schema/m.key.verification.start.yaml +46 -0
  251. data/data/matrix-spec/event-schemas/schema/m.key_backup.yaml +24 -0
  252. data/data/matrix-spec/event-schemas/schema/m.marked_unread.yaml +26 -0
  253. data/data/matrix-spec/event-schemas/schema/m.policy.rule.room.yaml +17 -0
  254. data/data/matrix-spec/event-schemas/schema/m.policy.rule.server.yaml +17 -0
  255. data/data/matrix-spec/event-schemas/schema/m.policy.rule.user.yaml +17 -0
  256. data/data/matrix-spec/event-schemas/schema/m.presence.yaml +50 -0
  257. data/data/matrix-spec/event-schemas/schema/m.push_rules.yaml +23 -0
  258. data/data/matrix-spec/event-schemas/schema/m.reaction.yaml +45 -0
  259. data/data/matrix-spec/event-schemas/schema/m.receipt.yaml +65 -0
  260. data/data/matrix-spec/event-schemas/schema/m.recent_emoji.yaml +29 -0
  261. data/data/matrix-spec/event-schemas/schema/m.room.avatar.yaml +29 -0
  262. data/data/matrix-spec/event-schemas/schema/m.room.canonical_alias.yaml +40 -0
  263. data/data/matrix-spec/event-schemas/schema/m.room.create.yaml +86 -0
  264. data/data/matrix-spec/event-schemas/schema/m.room.encrypted.yaml +91 -0
  265. data/data/matrix-spec/event-schemas/schema/m.room.encryption.yaml +38 -0
  266. data/data/matrix-spec/event-schemas/schema/m.room.guest_access.yaml +28 -0
  267. data/data/matrix-spec/event-schemas/schema/m.room.history_visibility.yaml +30 -0
  268. data/data/matrix-spec/event-schemas/schema/m.room.join_rules.yaml +78 -0
  269. data/data/matrix-spec/event-schemas/schema/m.room.member.yaml +174 -0
  270. data/data/matrix-spec/event-schemas/schema/m.room.message$m.audio.yaml +73 -0
  271. data/data/matrix-spec/event-schemas/schema/m.room.message$m.emote.yaml +36 -0
  272. data/data/matrix-spec/event-schemas/schema/m.room.message$m.file.yaml +85 -0
  273. data/data/matrix-spec/event-schemas/schema/m.room.message$m.image.yaml +63 -0
  274. data/data/matrix-spec/event-schemas/schema/m.room.message$m.key.verification.request.yaml +70 -0
  275. data/data/matrix-spec/event-schemas/schema/m.room.message$m.location.yaml +50 -0
  276. data/data/matrix-spec/event-schemas/schema/m.room.message$m.notice.yaml +36 -0
  277. data/data/matrix-spec/event-schemas/schema/m.room.message$m.server_notice.yaml +41 -0
  278. data/data/matrix-spec/event-schemas/schema/m.room.message$m.text.yaml +36 -0
  279. data/data/matrix-spec/event-schemas/schema/m.room.message$m.video.yaml +95 -0
  280. data/data/matrix-spec/event-schemas/schema/m.room.message.yaml +25 -0
  281. data/data/matrix-spec/event-schemas/schema/m.room.name.yaml +35 -0
  282. data/data/matrix-spec/event-schemas/schema/m.room.pinned_events.yaml +27 -0
  283. data/data/matrix-spec/event-schemas/schema/m.room.policy.yaml +41 -0
  284. data/data/matrix-spec/event-schemas/schema/m.room.power_levels.yaml +139 -0
  285. data/data/matrix-spec/event-schemas/schema/m.room.redaction.yaml +29 -0
  286. data/data/matrix-spec/event-schemas/schema/m.room.server_acl.yaml +88 -0
  287. data/data/matrix-spec/event-schemas/schema/m.room.third_party_invite.yaml +79 -0
  288. data/data/matrix-spec/event-schemas/schema/m.room.tombstone.yaml +29 -0
  289. data/data/matrix-spec/event-schemas/schema/m.room.topic.yaml +53 -0
  290. data/data/matrix-spec/event-schemas/schema/m.room_key.withheld.yaml +88 -0
  291. data/data/matrix-spec/event-schemas/schema/m.room_key.yaml +38 -0
  292. data/data/matrix-spec/event-schemas/schema/m.room_key_request.yaml +73 -0
  293. data/data/matrix-spec/event-schemas/schema/m.secret.request.yaml +42 -0
  294. data/data/matrix-spec/event-schemas/schema/m.secret.send.yaml +35 -0
  295. data/data/matrix-spec/event-schemas/schema/m.space.child.yaml +50 -0
  296. data/data/matrix-spec/event-schemas/schema/m.space.parent.yaml +36 -0
  297. data/data/matrix-spec/event-schemas/schema/m.sticker.yaml +36 -0
  298. data/data/matrix-spec/event-schemas/schema/m.tag.yaml +28 -0
  299. data/data/matrix-spec/event-schemas/schema/m.typing.yaml +29 -0
  300. data/lib/async/matrix/3.3/async_matrix_e2ee.so +0 -0
  301. data/lib/async/matrix/3.4/async_matrix_e2ee.so +0 -0
  302. data/lib/async/matrix/4.0/async_matrix_e2ee.so +0 -0
  303. data/lib/async/matrix/api/chain.rb +604 -0
  304. data/lib/async/matrix/api/concat.rb +107 -0
  305. data/lib/async/matrix/api/path_tree.rb +232 -0
  306. data/lib/async/matrix/api.rb +205 -0
  307. data/lib/async/matrix/auth_error.rb +20 -0
  308. data/lib/async/matrix/bad_json_error.rb +20 -0
  309. data/lib/async/matrix/client.rb +966 -0
  310. data/lib/async/matrix/config/vivify.rb +107 -0
  311. data/lib/async/matrix/config.rb +184 -0
  312. data/lib/async/matrix/connection.rb +19 -0
  313. data/lib/async/matrix/content.rb +106 -0
  314. data/lib/async/matrix/double_puppet_client.rb +82 -0
  315. data/lib/async/matrix/e2ee.rb +129 -0
  316. data/lib/async/matrix/endpoint.rb +57 -0
  317. data/lib/async/matrix/error.rb +40 -0
  318. data/lib/async/matrix/error_response.rb +37 -0
  319. data/lib/async/matrix/event.rb +197 -0
  320. data/lib/async/matrix/homeserver_error.rb +20 -0
  321. data/lib/async/matrix/invalid_endpoint_error.rb +20 -0
  322. data/lib/async/matrix/media_client.rb +181 -0
  323. data/lib/async/matrix/not_found_error.rb +20 -0
  324. data/lib/async/matrix/notifier.rb +108 -0
  325. data/lib/async/matrix/response_too_large_error.rb +20 -0
  326. data/lib/async/matrix/schema/registry.rb +381 -0
  327. data/lib/async/matrix/schema/validation_error.rb +232 -0
  328. data/lib/async/matrix/schema.rb +170 -0
  329. data/lib/async/matrix/server.rb +18 -0
  330. data/lib/async/matrix/stream.rb +18 -0
  331. data/lib/async/matrix/version.rb +10 -0
  332. data/lib/async/matrix.rb +15 -0
  333. metadata +494 -0
@@ -0,0 +1,604 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ require "string_builder"
7
+ require "erb"
8
+
9
+ module Async
10
+ module Matrix
11
+ module Api
12
+ # Wraps a StringBuilder to build Matrix API paths via method chaining,
13
+ # terminated by .get(), .post(), .put(), or .delete() which validate
14
+ # the path against the PathTree and fire the HTTP request.
15
+ #
16
+ # Inherits from BasicObject so that method names like `send`, `display`,
17
+ # `format`, `test`, etc. are not defined and fall through to
18
+ # method_missing, where they get recorded as URL path segments.
19
+ #
20
+ # Usage:
21
+ # chain = Chain.new(client: client, path_tree: tree, prefix: %w[_matrix client v3])
22
+ # chain.account.whoami.get
23
+ # chain.rooms("!abc:ex.com").send("m.room.message", "txn1").put(body: "hi")
24
+ # chain.rooms("!abc:ex.com").messages.get(dir: "b", limit: 10)
25
+ #
26
+ class Chain < ::BasicObject
27
+ # Paths that carry raw bytes instead of JSON. Matched by
28
+ # _binary_route? where * is a single-segment wildcard.
29
+ # The HTTP method determines the operation:
30
+ # GET → download (returns raw bytes)
31
+ # POST/PUT → upload (sends raw bytes)
32
+ BINARY_ROUTES = [
33
+ "/_matrix/media/v3/upload",
34
+ "/_matrix/media/v3/upload/*/*",
35
+ "/_matrix/media/v3/download/*/*",
36
+ "/_matrix/media/v3/download/*/*/*",
37
+ "/_matrix/media/v3/thumbnail/*/*",
38
+ "/_matrix/client/v1/media/download/*/*",
39
+ "/_matrix/client/v1/media/download/*/*/*",
40
+ "/_matrix/client/v1/media/thumbnail/*/*",
41
+ ].freeze
42
+
43
+ def initialize(client:, path_tree:, prefix: nil)
44
+ @client = client
45
+ @path_tree = path_tree
46
+ @prefix = prefix || ["_matrix", "client", "v3"]
47
+ @buffer = []
48
+ end
49
+
50
+ # ── Terminal HTTP methods ──────────────────────────────────
51
+
52
+ def get(**kwargs)
53
+ max_retries = kwargs.delete(:max_retries)
54
+ execute("GET", query: kwargs, max_retries: max_retries)
55
+ end
56
+
57
+ def post(body = nil, **kwargs)
58
+ content_type = kwargs.delete(:content_type)
59
+ max_retries = kwargs.delete(:max_retries)
60
+ query = _extract_query_params(kwargs)
61
+ execute("POST", body: body || kwargs, content_type: content_type, max_retries: max_retries, query: query)
62
+ end
63
+
64
+ def put(body = nil, **kwargs)
65
+ content_type = kwargs.delete(:content_type)
66
+ max_retries = kwargs.delete(:max_retries)
67
+ query = _extract_query_params(kwargs)
68
+ execute("PUT", body: body || kwargs, content_type: content_type, max_retries: max_retries, query: query)
69
+ end
70
+
71
+ def delete(**kwargs)
72
+ max_retries = kwargs.delete(:max_retries)
73
+ execute("DELETE", query: kwargs, max_retries: max_retries)
74
+ end
75
+
76
+ def patch(body = nil, **kwargs)
77
+ content_type = kwargs.delete(:content_type)
78
+ max_retries = kwargs.delete(:max_retries)
79
+ query = _extract_query_params(kwargs)
80
+ execute("PATCH", body: body || kwargs, content_type: content_type, max_retries: max_retries, query: query)
81
+ end
82
+
83
+ # ── Chain inspection ───────────────────────────────────────
84
+
85
+ def to_s
86
+ "/" + _build_full_segments.map { |s| _encode(s) }.join("/")
87
+ end
88
+
89
+ def inspect
90
+ segments = _build_full_segments
91
+ "#<Async::Matrix::Api::Chain path=/#{segments.join("/")}>"
92
+ end
93
+
94
+ def path_segments
95
+ _build_full_segments
96
+ end
97
+
98
+ # ── Everything else becomes a path segment ─────────────────
99
+
100
+ def method_missing(name, *args, **kwargs)
101
+ if kwargs.empty?
102
+ @buffer << [name.to_s, args]
103
+ else
104
+ @buffer << [name.to_s, [*args, kwargs]]
105
+ end
106
+ self
107
+ end
108
+
109
+ private
110
+
111
+ def execute(method, body: nil, query: nil, content_type: nil, max_retries: nil)
112
+ segments = _rewrite_version(_build_full_segments)
113
+ result = @path_tree.match(segments, method)
114
+
115
+ if !result[:valid]
116
+ path = "/" + segments.join("/")
117
+ available = result[:methods]
118
+ if available.empty?
119
+ ::Kernel.raise ::Async::Matrix::InvalidEndpointError.new(
120
+ "INVALID_ENDPOINT",
121
+ "No Matrix API endpoint matches: #{method} #{path}",
122
+ )
123
+ else
124
+ ::Kernel.raise ::Async::Matrix::InvalidEndpointError.new(
125
+ "METHOD_NOT_ALLOWED",
126
+ "#{method} not allowed for #{path}. Valid methods: #{available.map(&:upcase).join(", ")}",
127
+ )
128
+ end
129
+ end
130
+
131
+ path = "/" + segments.map { |s| _encode(s) }.join("/")
132
+
133
+ if query && !query.empty?
134
+ qs = query.map { |k, v| "#{_encode(k.to_s)}=#{_encode(v.to_s)}" }.join("&")
135
+ path = "#{path}?#{qs}"
136
+ end
137
+
138
+ if _binary_route?(segments)
139
+ case method
140
+ when "GET"
141
+ @client.media_client.download(path)
142
+ when "POST"
143
+ @client.media_client.upload(
144
+ "POST",
145
+ path,
146
+ body,
147
+ content_type || "application/octet-stream",
148
+ )
149
+ when "PUT"
150
+ @client.media_client.upload(
151
+ "PUT",
152
+ path,
153
+ body,
154
+ content_type || "application/octet-stream",
155
+ )
156
+ end
157
+ else
158
+ if max_retries
159
+ retry_opts = {max_retries: max_retries}
160
+ else
161
+ retry_opts = {}
162
+ end
163
+ case method
164
+ when "GET"
165
+ @client.get(path, **retry_opts)
166
+ when "POST"
167
+ @client.post(path, body || {}, **retry_opts)
168
+ when "PUT"
169
+ @client.put(path, body || {}, **retry_opts)
170
+ when "DELETE"
171
+ @client.request(
172
+ "DELETE",
173
+ path,
174
+ nil,
175
+ **retry_opts,
176
+ )
177
+ when "PATCH"
178
+ @client.request(
179
+ "PATCH",
180
+ path,
181
+ body || {},
182
+ **retry_opts,
183
+ )
184
+ end
185
+ end
186
+ end
187
+
188
+ # Rewrites version segments for endpoints that only exist at
189
+ # a different version than the gateway prefix provides.
190
+ # _matrix/media/v3/create → _matrix/media/v1/create
191
+ # _matrix/client/v3/media/... → _matrix/client/v1/media/...
192
+ def _rewrite_version(segments)
193
+ # POST /_matrix/media/v1/create (only exists at v1)
194
+ media_create = segments.length == 4 &&
195
+ segments[0] == "_matrix" && segments[1] == "media" &&
196
+ segments[2] == "v3" && segments[3] == "create"
197
+
198
+ # Authenticated media endpoints live at /_matrix/client/v1/media/...
199
+ client_media = segments.length >= 5 &&
200
+ segments[0] == "_matrix" && segments[1] == "client" &&
201
+ segments[2] == "v3" && segments[3] == "media"
202
+
203
+ if media_create || client_media
204
+ segments.dup.tap { |rewritten| rewritten[2] = "v1" }
205
+ else
206
+ segments
207
+ end
208
+ end
209
+
210
+ def _binary_route?(segments)
211
+ BINARY_ROUTES.any? do |pattern|
212
+ parts = pattern.split("/")
213
+ unless parts.length == segments.length + 1
214
+ next false
215
+ end # leading slash adds empty element
216
+ parts.shift # remove empty string from leading /
217
+ parts.length == segments.length &&
218
+ parts.zip(segments).all? { |pat, seg| pat == "*" || pat == seg }
219
+ end
220
+ end
221
+
222
+ def _extract_query_params(kwargs)
223
+ query = {}
224
+ kwargs.each_key do |k|
225
+ key_s = k.to_s
226
+ if key_s.start_with?("?")
227
+ query[key_s[1..]] = kwargs.delete(k)
228
+ end
229
+ end
230
+ query.empty? ? nil : query
231
+ end
232
+
233
+ def _build_full_segments
234
+ chain_segments = []
235
+ @buffer.each do |name, args|
236
+ chain_segments << name
237
+ if args.nil? || args.empty?
238
+ next
239
+ end
240
+ args.each do |arg|
241
+ if arg.is_a?(::Hash)
242
+ next
243
+ end
244
+ chain_segments << arg.to_s
245
+ end
246
+ end
247
+ @prefix + chain_segments
248
+ end
249
+
250
+ def _encode(value)
251
+ ::ERB::Util.url_encode(value.to_s)
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
257
+
258
+ __END__
259
+ describe "Async::Matrix::Api::Chain" do
260
+ def make_tree
261
+ tree = Async::Matrix::Api::PathTree.new
262
+ tree.insert(%w[_matrix client v3 account whoami], "get", "getAccountWhoami")
263
+ tree.insert(%w[_matrix client v3 createRoom], "post", "createRoom")
264
+ tree.insert(%w[_matrix client v3 rooms {roomId} ban], "post", "ban")
265
+ tree.insert(%w[_matrix client v3 rooms {roomId} state {eventType} {stateKey}], "get")
266
+ tree.insert(%w[_matrix client v3 rooms {roomId} state {eventType} {stateKey}], "put")
267
+ tree.insert(%w[_matrix client v3 rooms {roomId} messages], "get", "getRoomMessages")
268
+ tree.insert(%w[_matrix client v3 rooms {roomId} send {eventType} {txnId}], "put")
269
+ tree.insert(%w[_matrix client v3 profile {userId} displayname], "put", "setDisplayName")
270
+ tree
271
+ end
272
+
273
+ it "builds correct path segments for simple chain" do
274
+ chain = Async::Matrix::Api::Chain.new(
275
+ client: nil, path_tree: make_tree
276
+ )
277
+ chain.account.whoami
278
+ chain.path_segments.should == %w[_matrix client v3 account whoami]
279
+ end
280
+
281
+ it "builds correct path segments with args" do
282
+ chain = Async::Matrix::Api::Chain.new(
283
+ client: nil, path_tree: make_tree
284
+ )
285
+ chain.rooms("!abc:ex.com").ban
286
+ chain.path_segments.should == %w[_matrix client v3 rooms !abc:ex.com ban]
287
+ end
288
+
289
+ it "builds correct to_s with URL encoding" do
290
+ chain = Async::Matrix::Api::Chain.new(
291
+ client: nil, path_tree: make_tree
292
+ )
293
+ chain.rooms("!abc:ex.com").ban
294
+ chain.to_s.should == "/_matrix/client/v3/rooms/%21abc%3Aex.com/ban"
295
+ end
296
+
297
+ it "builds path for /rooms/{roomId}/send/{eventType}/{txnId}" do
298
+ chain = Async::Matrix::Api::Chain.new(
299
+ client: nil, path_tree: make_tree
300
+ )
301
+ chain.rooms("!abc:ex.com").send("m.room.message", "txn-123")
302
+ chain.path_segments.should == %w[_matrix client v3 rooms !abc:ex.com send m.room.message txn-123]
303
+ end
304
+
305
+ it "raises InvalidEndpointError for unknown path" do
306
+ chain = Async::Matrix::Api::Chain.new(
307
+ client: nil, path_tree: make_tree
308
+ )
309
+ chain.account.foobar
310
+ lambda { chain.get }.should.raise Async::Matrix::InvalidEndpointError
311
+ end
312
+
313
+ it "raises InvalidEndpointError for wrong HTTP method" do
314
+ chain = Async::Matrix::Api::Chain.new(
315
+ client: nil, path_tree: make_tree
316
+ )
317
+ chain.account.whoami
318
+ lambda { chain.post }.should.raise Async::Matrix::InvalidEndpointError
319
+ end
320
+
321
+ # ── Binary route detection ───────────────────────────────
322
+
323
+ def make_media_tree
324
+ tree = Async::Matrix::Api::PathTree.new
325
+ tree.insert(%w[_matrix media v3 upload], "post", "uploadContent")
326
+ tree.insert(%w[_matrix media v3 upload {serverName} {mediaId}], "put", "uploadContentToMXC")
327
+ tree.insert(%w[_matrix media v3 download {serverName} {mediaId}], "get", "getContent")
328
+ tree.insert(%w[_matrix media v3 download {serverName} {mediaId} {fileName}], "get", "getContentOverrideName")
329
+ tree.insert(%w[_matrix media v3 thumbnail {serverName} {mediaId}], "get", "getContentThumbnail")
330
+ tree.insert(%w[_matrix client v1 media download {serverName} {mediaId}], "get", "getContentAuthed")
331
+ tree.insert(%w[_matrix client v1 media download {serverName} {mediaId} {fileName}], "get", "getContentOverrideNameAuthed")
332
+ tree.insert(%w[_matrix client v1 media thumbnail {serverName} {mediaId}], "get", "getContentThumbnailAuthed")
333
+ tree
334
+ end
335
+
336
+ # Stub response object for download tests.
337
+ StubResponse = Struct.new(:body_bytes, :headers, :status) do
338
+ def initialize(body_bytes = "\xFF\xD8\xFF".b)
339
+ super(body_bytes, {"content-type" => "image/jpeg"}, 200)
340
+ end
341
+
342
+ def read
343
+ body_bytes
344
+ end
345
+ end
346
+
347
+ # Stub client with a stub media_client for testing dispatch.
348
+ StubMediaClient = Struct.new(:calls) do
349
+ def initialize
350
+ super([])
351
+ end
352
+
353
+ def upload(method, path, body, content_type)
354
+ calls << [:upload, method, path, body, content_type]
355
+ {"content_uri" => "mxc://example.com/abc123"}
356
+ end
357
+
358
+ def download(path)
359
+ calls << [:download, path]
360
+ StubResponse.new
361
+ end
362
+ end
363
+
364
+ StubClientWithMedia = Struct.new(:calls, :media_client) do
365
+ def initialize
366
+ super([], StubMediaClient.new)
367
+ end
368
+
369
+ def get(path, max_retries: nil)
370
+ calls << [:get, path, {max_retries: max_retries}]
371
+ {"stub" => true}
372
+ end
373
+
374
+ def post(path, body = {}, max_retries: nil)
375
+ calls << [:post, path, body, {max_retries: max_retries}]
376
+ {"stub" => true}
377
+ end
378
+
379
+ def put(path, body = {}, max_retries: nil)
380
+ calls << [:put, path, body, {max_retries: max_retries}]
381
+ {"stub" => true}
382
+ end
383
+
384
+ def request(method, path, body = nil, max_retries: nil)
385
+ calls << [method.downcase.to_sym, path, body, {max_retries: max_retries}]
386
+ {"stub" => true}
387
+ end
388
+ end
389
+
390
+ it "detects upload route and dispatches to media_client" do
391
+ client = StubClientWithMedia.new
392
+ chain = Async::Matrix::Api::Chain.new(
393
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix media v3]
394
+ )
395
+ chain.upload.post("image-bytes", content_type: "image/png")
396
+ client.media_client.calls.last[0].should == :upload
397
+ client.media_client.calls.last[1].should == "POST"
398
+ client.media_client.calls.last[3].should == "image-bytes"
399
+ client.media_client.calls.last[4].should == "image/png"
400
+ client.calls.should.be.empty
401
+ end
402
+
403
+ it "detects upload PUT route and dispatches to media_client" do
404
+ client = StubClientWithMedia.new
405
+ chain = Async::Matrix::Api::Chain.new(
406
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix media v3]
407
+ )
408
+ chain.upload("example.com", "abc123").put("image-bytes", content_type: "image/jpeg")
409
+ client.media_client.calls.last[0].should == :upload
410
+ client.media_client.calls.last[1].should == "PUT"
411
+ client.media_client.calls.last[4].should == "image/jpeg"
412
+ client.calls.should.be.empty
413
+ end
414
+
415
+ it "detects download route and dispatches to media_client" do
416
+ client = StubClientWithMedia.new
417
+ chain = Async::Matrix::Api::Chain.new(
418
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix media v3]
419
+ )
420
+ response = chain.download("example.com", "abc123").get
421
+ client.media_client.calls.last[0].should == :download
422
+ response.read.should == "\xFF\xD8\xFF".b
423
+ response.headers["content-type"].should == "image/jpeg"
424
+ client.calls.should.be.empty
425
+ end
426
+
427
+ it "detects download with filename route" do
428
+ client = StubClientWithMedia.new
429
+ chain = Async::Matrix::Api::Chain.new(
430
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix media v3]
431
+ )
432
+ chain.download("example.com", "abc123", "photo.jpg").get
433
+ client.media_client.calls.last[0].should == :download
434
+ end
435
+
436
+ it "detects thumbnail route and passes query params" do
437
+ client = StubClientWithMedia.new
438
+ chain = Async::Matrix::Api::Chain.new(
439
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix media v3]
440
+ )
441
+ chain.thumbnail("example.com", "abc123").get(width: 64, height: 64)
442
+ call = client.media_client.calls.last
443
+ call[0].should == :download
444
+ call[1].should.include "width=64"
445
+ call[1].should.include "height=64"
446
+ end
447
+
448
+ it "detects authed download route (client/v1 prefix)" do
449
+ client = StubClientWithMedia.new
450
+ chain = Async::Matrix::Api::Chain.new(
451
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix client v1]
452
+ )
453
+ chain.media.download("example.com", "abc123").get
454
+ client.media_client.calls.last[0].should == :download
455
+ end
456
+
457
+ it "does NOT route non-binary paths to media_client" do
458
+ client = StubClientWithMedia.new
459
+ tree = make_tree
460
+ chain = Async::Matrix::Api::Chain.new(
461
+ client: client, path_tree: tree
462
+ )
463
+ chain.account.whoami.get
464
+ client.calls.last[0].should == :get
465
+ client.media_client.calls.should.be.empty
466
+ end
467
+
468
+ it "defaults content_type to application/octet-stream for uploads" do
469
+ client = StubClientWithMedia.new
470
+ chain = Async::Matrix::Api::Chain.new(
471
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix media v3]
472
+ )
473
+ chain.upload.post("raw-bytes")
474
+ client.media_client.calls.last[4].should == "application/octet-stream"
475
+ end
476
+
477
+ # ── ?-prefixed query params on uploads ────────────────────
478
+
479
+ it "passes ?-prefixed kwargs as query params on upload POST" do
480
+ client = StubClientWithMedia.new
481
+ chain = Async::Matrix::Api::Chain.new(
482
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix media v3]
483
+ )
484
+ chain.upload.post("image-bytes", content_type: "image/png", "?filename": "photo.png")
485
+ call = client.media_client.calls.last
486
+ call[0].should == :upload
487
+ call[2].should.include "filename=photo.png"
488
+ call[4].should == "image/png"
489
+ end
490
+
491
+ it "passes ?-prefixed kwargs as query params on upload PUT" do
492
+ client = StubClientWithMedia.new
493
+ chain = Async::Matrix::Api::Chain.new(
494
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix media v3]
495
+ )
496
+ chain.upload("example.com", "abc123").put("bytes", content_type: "image/jpeg", "?filename": "pic.jpg")
497
+ call = client.media_client.calls.last
498
+ call[0].should == :upload
499
+ call[2].should.include "filename=pic.jpg"
500
+ end
501
+
502
+ # ── Version rewrites ──────────────────────────────────────
503
+
504
+ def make_full_media_tree
505
+ tree = make_media_tree
506
+ tree.insert(%w[_matrix media v1 create], "post", "createContent")
507
+ tree.insert(%w[_matrix media v3 config], "get", "getConfig")
508
+ tree.insert(%w[_matrix media v3 preview_url], "get", "getUrlPreview")
509
+ tree
510
+ end
511
+
512
+ it "rewrites media/v3/create to media/v1/create" do
513
+ client = StubClientWithMedia.new
514
+ chain = Async::Matrix::Api::Chain.new(
515
+ client: client, path_tree: make_full_media_tree, prefix: %w[_matrix media v3]
516
+ )
517
+ chain.create.post
518
+ call = client.calls.last
519
+ call[0].should == :post
520
+ call[1].should == "/_matrix/media/v1/create"
521
+ end
522
+
523
+ it "rewrites client/v3/media/download to client/v1/media/download" do
524
+ client = StubClientWithMedia.new
525
+ chain = Async::Matrix::Api::Chain.new(
526
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix client v3]
527
+ )
528
+ chain.media.download("example.com", "abc123").get
529
+ call = client.media_client.calls.last
530
+ call[0].should == :download
531
+ call[1].should.include "/_matrix/client/v1/media/download/"
532
+ end
533
+
534
+ it "rewrites client/v3/media/thumbnail to client/v1/media/thumbnail" do
535
+ client = StubClientWithMedia.new
536
+ chain = Async::Matrix::Api::Chain.new(
537
+ client: client, path_tree: make_media_tree, prefix: %w[_matrix client v3]
538
+ )
539
+ chain.media.thumbnail("example.com", "abc123").get(width: 32, height: 32)
540
+ call = client.media_client.calls.last
541
+ call[0].should == :download
542
+ call[1].should.include "/_matrix/client/v1/media/thumbnail/"
543
+ end
544
+
545
+ it "does NOT rewrite non-media client/v3 paths" do
546
+ client = StubClientWithMedia.new
547
+ tree = make_tree
548
+ chain = Async::Matrix::Api::Chain.new(
549
+ client: client, path_tree: tree, prefix: %w[_matrix client v3]
550
+ )
551
+ chain.account.whoami.get
552
+ call = client.calls.last
553
+ call[1].should == "/_matrix/client/v3/account/whoami"
554
+ end
555
+
556
+ it "does NOT rewrite media/v3 paths that are not create" do
557
+ client = StubClientWithMedia.new
558
+ chain = Async::Matrix::Api::Chain.new(
559
+ client: client, path_tree: make_full_media_tree, prefix: %w[_matrix media v3]
560
+ )
561
+ chain.config.get
562
+ call = client.calls.last
563
+ call[0].should == :get
564
+ call[1].should == "/_matrix/media/v3/config"
565
+ end
566
+
567
+ # ── max_retries forwarding ─────────────────────────────────
568
+
569
+ it "forwards max_retries on get" do
570
+ client = StubClientWithMedia.new
571
+ chain = Async::Matrix::Api::Chain.new(
572
+ client: client, path_tree: make_tree
573
+ )
574
+ chain.account.whoami.get(max_retries: 0)
575
+ client.calls.last.last[:max_retries].should == 0
576
+ end
577
+
578
+ it "forwards max_retries on post" do
579
+ client = StubClientWithMedia.new
580
+ chain = Async::Matrix::Api::Chain.new(
581
+ client: client, path_tree: make_tree
582
+ )
583
+ chain.createRoom.post({name: "Test"}, max_retries: 1)
584
+ client.calls.last.last[:max_retries].should == 1
585
+ end
586
+
587
+ it "forwards max_retries on put" do
588
+ client = StubClientWithMedia.new
589
+ chain = Async::Matrix::Api::Chain.new(
590
+ client: client, path_tree: make_tree
591
+ )
592
+ chain.profile("@user:ex.com").displayname.put({displayname: "Bob"}, max_retries: 2)
593
+ client.calls.last.last[:max_retries].should == 2
594
+ end
595
+
596
+ it "forwards nil max_retries by default" do
597
+ client = StubClientWithMedia.new
598
+ chain = Async::Matrix::Api::Chain.new(
599
+ client: client, path_tree: make_tree
600
+ )
601
+ chain.account.whoami.get
602
+ client.calls.last.last[:max_retries].should.be.nil
603
+ end
604
+ end