async-matrix 2.0.1-aarch64-mingw-ucrt

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 (371) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +200 -0
  3. data/README.md +133 -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/discord/api/path_tree.rb +127 -0
  301. data/lib/async/discord/api.rb +151 -0
  302. data/lib/async/discord/client.rb +283 -0
  303. data/lib/async/discord/error.rb +84 -0
  304. data/lib/async/discord/gateway.rb +359 -0
  305. data/lib/async/discord.rb +15 -0
  306. data/lib/async/matrix/3.4/async_matrix_e2ee.so +0 -0
  307. data/lib/async/matrix/4.0/async_matrix_e2ee.so +0 -0
  308. data/lib/async/matrix/api/chain.rb +578 -0
  309. data/lib/async/matrix/api/concat.rb +101 -0
  310. data/lib/async/matrix/api/path_tree.rb +205 -0
  311. data/lib/async/matrix/api.rb +200 -0
  312. data/lib/async/matrix/application_service/bot.rb +232 -0
  313. data/lib/async/matrix/application_service/config/schema/analytics.json +21 -0
  314. data/lib/async/matrix/application_service/config/schema/appservice.json +82 -0
  315. data/lib/async/matrix/application_service/config/schema/backfill.json +91 -0
  316. data/lib/async/matrix/application_service/config/schema/bridge.json +209 -0
  317. data/lib/async/matrix/application_service/config/schema/config.json +61 -0
  318. data/lib/async/matrix/application_service/config/schema/database.json +38 -0
  319. data/lib/async/matrix/application_service/config/schema/direct_media.json +35 -0
  320. data/lib/async/matrix/application_service/config/schema/double_puppet.json +24 -0
  321. data/lib/async/matrix/application_service/config/schema/encryption.json +164 -0
  322. data/lib/async/matrix/application_service/config/schema/homeserver.json +58 -0
  323. data/lib/async/matrix/application_service/config/schema/logging.json +50 -0
  324. data/lib/async/matrix/application_service/config/schema/management_room_texts.json +25 -0
  325. data/lib/async/matrix/application_service/config/schema/matrix.json +45 -0
  326. data/lib/async/matrix/application_service/config/schema/permissions.json +54 -0
  327. data/lib/async/matrix/application_service/config/schema/provisioning.json +23 -0
  328. data/lib/async/matrix/application_service/config/schema/public_media.json +39 -0
  329. data/lib/async/matrix/application_service/config/schema/relay.json +43 -0
  330. data/lib/async/matrix/application_service/config/vivify.rb +109 -0
  331. data/lib/async/matrix/application_service/config.rb +225 -0
  332. data/lib/async/matrix/application_service/dispatcher.rb +185 -0
  333. data/lib/async/matrix/application_service/error_response.rb +37 -0
  334. data/lib/async/matrix/application_service/event.rb +285 -0
  335. data/lib/async/matrix/application_service/server.rb +430 -0
  336. data/lib/async/matrix/application_service/transaction.rb +66 -0
  337. data/lib/async/matrix/application_service/transaction_handler.rb +185 -0
  338. data/lib/async/matrix/application_service/transaction_store.rb +80 -0
  339. data/lib/async/matrix/bridge/discord/db/connection.rb +141 -0
  340. data/lib/async/matrix/bridge/discord/db/file.rb +118 -0
  341. data/lib/async/matrix/bridge/discord/db/guild.rb +120 -0
  342. data/lib/async/matrix/bridge/discord/db/message.rb +160 -0
  343. data/lib/async/matrix/bridge/discord/db/migrations/001_create_users.rb +14 -0
  344. data/lib/async/matrix/bridge/discord/db/migrations/002_create_guilds.rb +14 -0
  345. data/lib/async/matrix/bridge/discord/db/migrations/003_create_portals.rb +23 -0
  346. data/lib/async/matrix/bridge/discord/db/migrations/004_create_puppets.rb +19 -0
  347. data/lib/async/matrix/bridge/discord/db/migrations/005_create_messages.rb +20 -0
  348. data/lib/async/matrix/bridge/discord/db/migrations/006_create_reactions.rb +19 -0
  349. data/lib/async/matrix/bridge/discord/db/migrations/007_create_files.rb +18 -0
  350. data/lib/async/matrix/bridge/discord/db/portal.rb +150 -0
  351. data/lib/async/matrix/bridge/discord/db/puppet.rb +128 -0
  352. data/lib/async/matrix/bridge/discord/db/reaction.rb +165 -0
  353. data/lib/async/matrix/bridge/discord/db/schema.rb +18 -0
  354. data/lib/async/matrix/bridge/discord/db/user.rb +112 -0
  355. data/lib/async/matrix/bridge/discord/db.rb +138 -0
  356. data/lib/async/matrix/client.rb +934 -0
  357. data/lib/async/matrix/connection.rb +19 -0
  358. data/lib/async/matrix/double_puppet_client.rb +82 -0
  359. data/lib/async/matrix/e2ee.rb +92 -0
  360. data/lib/async/matrix/endpoint.rb +57 -0
  361. data/lib/async/matrix/error.rb +67 -0
  362. data/lib/async/matrix/media_client.rb +170 -0
  363. data/lib/async/matrix/notifier.rb +104 -0
  364. data/lib/async/matrix/schema/registry.rb +354 -0
  365. data/lib/async/matrix/schema/validation_error.rb +225 -0
  366. data/lib/async/matrix/schema.rb +170 -0
  367. data/lib/async/matrix/server.rb +18 -0
  368. data/lib/async/matrix/stream.rb +18 -0
  369. data/lib/async/matrix/version.rb +10 -0
  370. data/lib/async/matrix.rb +22 -0
  371. metadata +587 -0
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ change do
5
+ create_table(:messages) do
6
+ primary_key :id
7
+ String :discord_id, null: false
8
+ String :discord_attachment_id, null: false, default: ""
9
+ String :discord_channel_id, null: false
10
+ String :discord_channel_receiver, null: false, default: ""
11
+ String :discord_sender, null: false
12
+ String :mxid, null: false
13
+ Bignum :timestamp, null: false
14
+ String :discord_thread_id
15
+
16
+ unique [:discord_id, :discord_attachment_id, :discord_channel_id, :discord_channel_receiver]
17
+ index :mxid
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ change do
5
+ create_table(:reactions) do
6
+ primary_key :id
7
+ String :discord_message_id, null: false
8
+ String :discord_sender, null: false
9
+ String :discord_emoji_name, null: false
10
+ String :mxid, null: false
11
+ String :discord_channel_id, null: false
12
+ String :discord_channel_receiver, null: false, default: ""
13
+ String :discord_thread_id
14
+
15
+ unique [:discord_message_id, :discord_sender, :discord_emoji_name]
16
+ index :mxid
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ change do
5
+ create_table(:files) do
6
+ String :url, null: false
7
+ TrueClass :encrypted, null: false, default: false
8
+ String :mxc, null: false
9
+ String :mime_type
10
+ Bignum :size
11
+ Integer :width
12
+ Integer :height
13
+ String :decryption_info
14
+
15
+ primary_key [:url, :encrypted]
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,150 @@
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_relative "schema"
7
+
8
+ module Async
9
+ module Matrix
10
+ module Bridge
11
+ module Discord
12
+ module DB
13
+ # Maps a Discord channel to a Matrix room.
14
+ #
15
+ # Uses a composite primary key of (discord_id, receiver). For guild
16
+ # channels, receiver is an empty string. For DMs, receiver is the
17
+ # Discord user ID of the bridge user who owns the portal.
18
+ #
19
+ # portal = Portal.create(discord_id: "chan123", receiver: "", mxid: "!room:x")
20
+ # portal.guild # => Guild or nil
21
+ # portal.messages # => [Message, ...]
22
+ #
23
+ class Portal < Sequel::Model
24
+ unrestrict_primary_key
25
+
26
+ many_to_one :guild,
27
+ class: "Async::Matrix::Bridge::Discord::DB::Guild",
28
+ key: :discord_guild_id,
29
+ primary_key: :discord_id
30
+
31
+ one_to_many :messages,
32
+ class: "Async::Matrix::Bridge::Discord::DB::Message",
33
+ key: [:discord_channel_id, :discord_channel_receiver],
34
+ primary_key: [:discord_id, :receiver]
35
+
36
+ def validate
37
+ super
38
+ errors.add(:discord_id, "cannot be empty") if discord_id.nil? || discord_id.empty?
39
+ end
40
+
41
+ # Is this a DM portal? (has a receiver)
42
+ def dm?
43
+ receiver && !receiver.empty?
44
+ end
45
+
46
+ # Is this a guild channel portal?
47
+ def guild_channel?
48
+ !dm?
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ __END__
58
+ describe "Async::Matrix::Bridge::Discord::DB::Portal" do
59
+ def setup_db
60
+ db = Sequel.sqlite
61
+ Sequel::Migrator.run(db, File.join(__dir__, "migrations"))
62
+ db
63
+ end
64
+
65
+ def set_datasets(db)
66
+ Async::Matrix::Bridge::Discord::DB::Portal.dataset = db[:portals]
67
+ Async::Matrix::Bridge::Discord::DB::Guild.dataset = db[:guilds]
68
+ Async::Matrix::Bridge::Discord::DB::Message.dataset = db[:messages]
69
+ end
70
+
71
+ it "creates a guild channel portal" do
72
+ db = setup_db
73
+ set_datasets(db)
74
+
75
+ portal = Async::Matrix::Bridge::Discord::DB::Portal.create(
76
+ discord_id: "chan1", receiver: "", mxid: "!room:x", name: "general"
77
+ )
78
+ portal.discord_id.should == "chan1"
79
+ portal.receiver.should == ""
80
+ portal.guild_channel?.should == true
81
+ portal.dm?.should == false
82
+ db.disconnect
83
+ end
84
+
85
+ it "creates a DM portal with receiver" do
86
+ db = setup_db
87
+ set_datasets(db)
88
+
89
+ portal = Async::Matrix::Bridge::Discord::DB::Portal.create(
90
+ discord_id: "dm1", receiver: "user123", mxid: "!dm:x"
91
+ )
92
+ portal.dm?.should == true
93
+ portal.guild_channel?.should == false
94
+ db.disconnect
95
+ end
96
+
97
+ it "finds by composite primary key" do
98
+ db = setup_db
99
+ set_datasets(db)
100
+
101
+ Async::Matrix::Bridge::Discord::DB::Portal.create(discord_id: "c1", receiver: "")
102
+ Async::Matrix::Bridge::Discord::DB::Portal.create(discord_id: "c1", receiver: "u1")
103
+
104
+ found = Async::Matrix::Bridge::Discord::DB::Portal["c1", ""]
105
+ found.should.not.be.nil
106
+ found.receiver.should == ""
107
+
108
+ found2 = Async::Matrix::Bridge::Discord::DB::Portal["c1", "u1"]
109
+ found2.receiver.should == "u1"
110
+ db.disconnect
111
+ end
112
+
113
+ it "associates with a guild" do
114
+ db = setup_db
115
+ set_datasets(db)
116
+
117
+ guild = Async::Matrix::Bridge::Discord::DB::Guild.create(discord_id: "g_assoc", name: "Guild")
118
+ portal = Async::Matrix::Bridge::Discord::DB::Portal.create(
119
+ discord_id: "c_assoc", receiver: "", discord_guild_id: "g_assoc"
120
+ )
121
+ # Query through the db directly to avoid races with parallel tests
122
+ # that rebind the class-level dataset on Sequel models.
123
+ portal.discord_guild_id.should == "g_assoc"
124
+ linked_guild = db[:guilds].where(discord_id: portal.discord_guild_id).first
125
+ linked_guild[:discord_id].should == "g_assoc"
126
+ linked_portals = db[:portals].where(discord_guild_id: guild.discord_id).all
127
+ linked_portals.length.should == 1
128
+ db.disconnect
129
+ end
130
+
131
+ it "enforces unique mxid" do
132
+ db = setup_db
133
+ set_datasets(db)
134
+
135
+ Async::Matrix::Bridge::Discord::DB::Portal.create(discord_id: "a", receiver: "", mxid: "!r:x")
136
+ lambda {
137
+ Async::Matrix::Bridge::Discord::DB::Portal.create(discord_id: "b", receiver: "", mxid: "!r:x")
138
+ }.should.raise(Sequel::UniqueConstraintViolation)
139
+ db.disconnect
140
+ end
141
+
142
+ it "defaults encrypted to false" do
143
+ db = setup_db
144
+ set_datasets(db)
145
+
146
+ portal = Async::Matrix::Bridge::Discord::DB::Portal.create(discord_id: "e1", receiver: "")
147
+ portal.encrypted.should == false
148
+ db.disconnect
149
+ end
150
+ end
@@ -0,0 +1,128 @@
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_relative "schema"
7
+
8
+ module Async
9
+ module Matrix
10
+ module Bridge
11
+ module Discord
12
+ module DB
13
+ # Maps a Discord user to a Matrix ghost user.
14
+ #
15
+ # The ghost's Matrix ID is derived from the username template in the
16
+ # bridge config (e.g., @discord_123456:example.com). This model
17
+ # tracks the Discord user's profile info for syncing to Matrix.
18
+ #
19
+ # puppet = Puppet.create(discord_id: "123", username: "alice", name: "Alice")
20
+ # puppet.is_bot? # => false
21
+ # puppet.double_puppet? # => true (if custom_mxid is set)
22
+ #
23
+ class Puppet < Sequel::Model
24
+ unrestrict_primary_key
25
+
26
+ def validate
27
+ super
28
+ errors.add(:discord_id, "cannot be empty") if discord_id.nil? || discord_id.empty?
29
+ end
30
+
31
+ # Is this puppet configured for double puppeting?
32
+ def double_puppet?
33
+ !custom_mxid.nil? && !custom_mxid.empty?
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ __END__
43
+ describe "Async::Matrix::Bridge::Discord::DB::Puppet" do
44
+ def setup_db
45
+ db = Sequel.sqlite
46
+ Sequel::Migrator.run(db, File.join(__dir__, "migrations"))
47
+ db
48
+ end
49
+
50
+ it "creates and retrieves a puppet" do
51
+ db = setup_db
52
+ Async::Matrix::Bridge::Discord::DB::Puppet.dataset = db[:puppets]
53
+
54
+ puppet = Async::Matrix::Bridge::Discord::DB::Puppet.create(
55
+ discord_id: "123",
56
+ name: "Alice",
57
+ username: "alice",
58
+ global_name: "Alice Wonderland"
59
+ )
60
+ puppet.discord_id.should == "123"
61
+ puppet.name.should == "Alice"
62
+ puppet.username.should == "alice"
63
+ puppet.global_name.should == "Alice Wonderland"
64
+ db.disconnect
65
+ end
66
+
67
+ it "defaults boolean flags to false" do
68
+ db = setup_db
69
+ Async::Matrix::Bridge::Discord::DB::Puppet.dataset = db[:puppets]
70
+
71
+ puppet = Async::Matrix::Bridge::Discord::DB::Puppet.create(discord_id: "200")
72
+ puppet.is_bot.should == false
73
+ puppet.is_webhook.should == false
74
+ puppet.contact_info_set.should == false
75
+ db.disconnect
76
+ end
77
+
78
+ it "tracks bot and webhook puppets" do
79
+ db = setup_db
80
+ Async::Matrix::Bridge::Discord::DB::Puppet.dataset = db[:puppets]
81
+
82
+ bot = Async::Matrix::Bridge::Discord::DB::Puppet.create(discord_id: "300", is_bot: true)
83
+ bot.is_bot.should == true
84
+
85
+ webhook = Async::Matrix::Bridge::Discord::DB::Puppet.create(discord_id: "301", is_webhook: true)
86
+ webhook.is_webhook.should == true
87
+ db.disconnect
88
+ end
89
+
90
+ it "detects double puppet configuration" do
91
+ db = setup_db
92
+ Async::Matrix::Bridge::Discord::DB::Puppet.dataset = db[:puppets]
93
+
94
+ regular = Async::Matrix::Bridge::Discord::DB::Puppet.create(discord_id: "400")
95
+ regular.double_puppet?.should == false
96
+
97
+ double = Async::Matrix::Bridge::Discord::DB::Puppet.create(
98
+ discord_id: "401",
99
+ custom_mxid: "@alice:example.com",
100
+ access_token: "syt_token"
101
+ )
102
+ double.double_puppet?.should == true
103
+ double.access_token.should == "syt_token"
104
+ db.disconnect
105
+ end
106
+
107
+ it "validates discord_id is present" do
108
+ db = setup_db
109
+ Async::Matrix::Bridge::Discord::DB::Puppet.dataset = db[:puppets]
110
+
111
+ puppet = Async::Matrix::Bridge::Discord::DB::Puppet.new(discord_id: "")
112
+ puppet.valid?.should == false
113
+ puppet.errors[:discord_id].should.not.be.empty
114
+ db.disconnect
115
+ end
116
+
117
+ it "updates avatar info" do
118
+ db = setup_db
119
+ Async::Matrix::Bridge::Discord::DB::Puppet.dataset = db[:puppets]
120
+
121
+ puppet = Async::Matrix::Bridge::Discord::DB::Puppet.create(discord_id: "500")
122
+ puppet.update(avatar_hash: "abc123", avatar_url: "mxc://example.com/abc")
123
+ puppet.refresh
124
+ puppet.avatar_hash.should == "abc123"
125
+ puppet.avatar_url.should == "mxc://example.com/abc"
126
+ db.disconnect
127
+ end
128
+ end
@@ -0,0 +1,165 @@
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_relative "schema"
7
+
8
+ module Async
9
+ module Matrix
10
+ module Bridge
11
+ module Discord
12
+ module DB
13
+ # Maps a Discord reaction to a Matrix reaction event.
14
+ #
15
+ # Uniquely identified by (discord_message_id, discord_sender,
16
+ # discord_emoji_name) — one reaction per emoji per user per message.
17
+ #
18
+ # reaction = Reaction.create(
19
+ # discord_message_id: "msg1", discord_sender: "user1",
20
+ # discord_emoji_name: "\u{1f44d}", mxid: "$react1",
21
+ # discord_channel_id: "ch1"
22
+ # )
23
+ #
24
+ class Reaction < Sequel::Model
25
+ def validate
26
+ super
27
+ errors.add(:discord_message_id, "cannot be empty") if discord_message_id.nil? || discord_message_id.empty?
28
+ errors.add(:discord_sender, "cannot be empty") if discord_sender.nil? || discord_sender.empty?
29
+ errors.add(:discord_emoji_name, "cannot be empty") if discord_emoji_name.nil? || discord_emoji_name.empty?
30
+ errors.add(:mxid, "cannot be empty") if mxid.nil? || mxid.empty?
31
+ end
32
+
33
+ # Find all reactions on a Discord message.
34
+ def self.by_discord_message(message_id, channel_id, receiver = "")
35
+ where(
36
+ discord_message_id: message_id,
37
+ discord_channel_id: channel_id,
38
+ discord_channel_receiver: receiver
39
+ ).all
40
+ end
41
+
42
+ # Find a specific reaction by its Matrix event ID.
43
+ def self.by_mxid(mxid)
44
+ first(mxid: mxid)
45
+ end
46
+
47
+ # Find a specific reaction by Discord compound key.
48
+ def self.by_discord_key(message_id:, sender:, emoji_name:)
49
+ first(
50
+ discord_message_id: message_id,
51
+ discord_sender: sender,
52
+ discord_emoji_name: emoji_name
53
+ )
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ __END__
63
+ describe "Async::Matrix::Bridge::Discord::DB::Reaction" do
64
+ def setup_db
65
+ db = Sequel.sqlite
66
+ Sequel::Migrator.run(db, File.join(__dir__, "migrations"))
67
+ db
68
+ end
69
+
70
+ it "creates and retrieves a reaction" do
71
+ db = setup_db
72
+ Async::Matrix::Bridge::Discord::DB::Reaction.dataset = db[:reactions]
73
+
74
+ reaction = Async::Matrix::Bridge::Discord::DB::Reaction.create(
75
+ discord_message_id: "msg1",
76
+ discord_sender: "user1",
77
+ discord_emoji_name: "\u{1f44d}",
78
+ mxid: "$react1",
79
+ discord_channel_id: "ch1"
80
+ )
81
+ reaction.discord_emoji_name.should == "\u{1f44d}"
82
+ reaction.mxid.should == "$react1"
83
+ db.disconnect
84
+ end
85
+
86
+ it "finds reactions by discord message" do
87
+ db = setup_db
88
+ Async::Matrix::Bridge::Discord::DB::Reaction.dataset = db[:reactions]
89
+
90
+ Async::Matrix::Bridge::Discord::DB::Reaction.create(
91
+ discord_message_id: "msg2", discord_sender: "u1",
92
+ discord_emoji_name: "\u{1f44d}", mxid: "$r1", discord_channel_id: "ch1"
93
+ )
94
+ Async::Matrix::Bridge::Discord::DB::Reaction.create(
95
+ discord_message_id: "msg2", discord_sender: "u2",
96
+ discord_emoji_name: "\u{2764}", mxid: "$r2", discord_channel_id: "ch1"
97
+ )
98
+
99
+ reactions = Async::Matrix::Bridge::Discord::DB::Reaction.by_discord_message("msg2", "ch1")
100
+ reactions.length.should == 2
101
+ db.disconnect
102
+ end
103
+
104
+ it "finds by Discord compound key" do
105
+ db = setup_db
106
+ Async::Matrix::Bridge::Discord::DB::Reaction.dataset = db[:reactions]
107
+
108
+ Async::Matrix::Bridge::Discord::DB::Reaction.create(
109
+ discord_message_id: "msg3", discord_sender: "u1",
110
+ discord_emoji_name: "custom_emoji", mxid: "$r3", discord_channel_id: "ch1"
111
+ )
112
+
113
+ found = Async::Matrix::Bridge::Discord::DB::Reaction.by_discord_key(
114
+ message_id: "msg3", sender: "u1", emoji_name: "custom_emoji"
115
+ )
116
+ found.should.not.be.nil
117
+ found.mxid.should == "$r3"
118
+ db.disconnect
119
+ end
120
+
121
+ it "finds by Matrix event ID" do
122
+ db = setup_db
123
+ Async::Matrix::Bridge::Discord::DB::Reaction.dataset = db[:reactions]
124
+
125
+ Async::Matrix::Bridge::Discord::DB::Reaction.create(
126
+ discord_message_id: "msg4", discord_sender: "u1",
127
+ discord_emoji_name: "x", mxid: "$find_react", discord_channel_id: "ch1"
128
+ )
129
+
130
+ found = Async::Matrix::Bridge::Discord::DB::Reaction.by_mxid("$find_react")
131
+ found.discord_message_id.should == "msg4"
132
+ db.disconnect
133
+ end
134
+
135
+ it "enforces unique reaction per user per emoji per message" do
136
+ db = setup_db
137
+ Async::Matrix::Bridge::Discord::DB::Reaction.dataset = db[:reactions]
138
+
139
+ Async::Matrix::Bridge::Discord::DB::Reaction.create(
140
+ discord_message_id: "msg5", discord_sender: "u1",
141
+ discord_emoji_name: "x", mxid: "$r5", discord_channel_id: "ch1"
142
+ )
143
+ lambda {
144
+ Async::Matrix::Bridge::Discord::DB::Reaction.create(
145
+ discord_message_id: "msg5", discord_sender: "u1",
146
+ discord_emoji_name: "x", mxid: "$r6", discord_channel_id: "ch1"
147
+ )
148
+ }.should.raise(Sequel::UniqueConstraintViolation)
149
+ db.disconnect
150
+ end
151
+
152
+ it "validates required fields" do
153
+ db = setup_db
154
+ Async::Matrix::Bridge::Discord::DB::Reaction.dataset = db[:reactions]
155
+
156
+ r = Async::Matrix::Bridge::Discord::DB::Reaction.new(
157
+ discord_message_id: "", discord_sender: "",
158
+ discord_emoji_name: "", mxid: ""
159
+ )
160
+ r.valid?.should == false
161
+ r.errors[:discord_message_id].should.not.be.empty
162
+ r.errors[:mxid].should.not.be.empty
163
+ db.disconnect
164
+ end
165
+ end
@@ -0,0 +1,18 @@
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 "sequel"
7
+
8
+ # Sequel::Model requires a database connection at subclass definition time.
9
+ # Set a placeholder in-memory SQLite so models can be defined at load time.
10
+ # The real database is bound later via DB.connect / DB.bind_models.
11
+ #
12
+ # require_valid_table = false suppresses the column introspection that Sequel
13
+ # normally does on inheritance — critical because the placeholder DB has no
14
+ # tables.
15
+ unless Sequel::Model.instance_variable_get(:@db)
16
+ Sequel::Model.db = Sequel.sqlite
17
+ Sequel::Model.require_valid_table = false
18
+ end
@@ -0,0 +1,112 @@
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_relative "schema"
7
+
8
+ module Async
9
+ module Matrix
10
+ module Bridge
11
+ module Discord
12
+ module DB
13
+ # Maps a Matrix user to their Discord identity and session state.
14
+ #
15
+ # user = User.create(mxid: "@alice:example.com", discord_id: "123456789")
16
+ # user.discord_id # => "123456789"
17
+ # user.space_room # => "!space:example.com"
18
+ # user.portals # => [Portal, ...]
19
+ #
20
+ class User < Sequel::Model
21
+ unrestrict_primary_key
22
+
23
+ one_to_many :portals,
24
+ class: "Async::Matrix::Bridge::Discord::DB::Portal",
25
+ key: :receiver,
26
+ primary_key: :discord_id
27
+
28
+ def validate
29
+ super
30
+ errors.add(:mxid, "cannot be empty") if mxid.nil? || mxid.empty?
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ __END__
40
+ describe "Async::Matrix::Bridge::Discord::DB::User" do
41
+ def setup_db
42
+ db = Sequel.sqlite
43
+ Sequel::Migrator.run(db, File.join(__dir__, "migrations"))
44
+ db
45
+ end
46
+
47
+ it "creates and retrieves a user by mxid" do
48
+ db = setup_db
49
+ Async::Matrix::Bridge::Discord::DB::User.dataset = db[:users]
50
+
51
+ user = Async::Matrix::Bridge::Discord::DB::User.create(
52
+ mxid: "@alice:example.com",
53
+ discord_id: "123456789"
54
+ )
55
+ user.mxid.should == "@alice:example.com"
56
+ user.discord_id.should == "123456789"
57
+
58
+ found = Async::Matrix::Bridge::Discord::DB::User["@alice:example.com"]
59
+ found.discord_id.should == "123456789"
60
+ db.disconnect
61
+ end
62
+
63
+ it "stores optional session fields" do
64
+ db = setup_db
65
+ Async::Matrix::Bridge::Discord::DB::User.dataset = db[:users]
66
+
67
+ user = Async::Matrix::Bridge::Discord::DB::User.create(
68
+ mxid: "@bob:example.com",
69
+ discord_token: "secret_token",
70
+ management_room: "!mgmt:example.com",
71
+ space_room: "!space:example.com",
72
+ dm_space_room: "!dm:example.com"
73
+ )
74
+ user.discord_token.should == "secret_token"
75
+ user.management_room.should == "!mgmt:example.com"
76
+ user.space_room.should == "!space:example.com"
77
+ user.dm_space_room.should == "!dm:example.com"
78
+ db.disconnect
79
+ end
80
+
81
+ it "enforces unique discord_id" do
82
+ db = setup_db
83
+ Async::Matrix::Bridge::Discord::DB::User.dataset = db[:users]
84
+
85
+ Async::Matrix::Bridge::Discord::DB::User.create(mxid: "@a:x", discord_id: "111")
86
+ lambda {
87
+ Async::Matrix::Bridge::Discord::DB::User.create(mxid: "@b:x", discord_id: "111")
88
+ }.should.raise(Sequel::UniqueConstraintViolation)
89
+ db.disconnect
90
+ end
91
+
92
+ it "validates mxid is present" do
93
+ db = setup_db
94
+ Async::Matrix::Bridge::Discord::DB::User.dataset = db[:users]
95
+
96
+ user = Async::Matrix::Bridge::Discord::DB::User.new(mxid: "")
97
+ user.valid?.should == false
98
+ user.errors[:mxid].should.not.be.empty
99
+ db.disconnect
100
+ end
101
+
102
+ it "updates discord token" do
103
+ db = setup_db
104
+ Async::Matrix::Bridge::Discord::DB::User.dataset = db[:users]
105
+
106
+ user = Async::Matrix::Bridge::Discord::DB::User.create(mxid: "@c:x")
107
+ user.update(discord_token: "new_token")
108
+ user.refresh
109
+ user.discord_token.should == "new_token"
110
+ db.disconnect
111
+ end
112
+ end