support rich replies, support basic m.mentions
This commit is contained in:
		
							parent
							
								
									5326b7d6be
								
							
						
					
					
						commit
						328ae74b61
					
				
					 7 changed files with 689 additions and 16 deletions
				
			
		| 
						 | 
					@ -27,7 +27,7 @@ async function sendMessage(message, guild) {
 | 
				
			||||||
		await registerUser.syncUser(message.author, message.member, message.guild_id, roomID)
 | 
							await registerUser.syncUser(message.author, message.member, message.guild_id, roomID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const events = await messageToEvent.messageToEvent(message, guild)
 | 
						const events = await messageToEvent.messageToEvent(message, guild, api)
 | 
				
			||||||
	const eventIDs = []
 | 
						const eventIDs = []
 | 
				
			||||||
	let eventPart = 0 // 0 is primary, 1 is supporting
 | 
						let eventPart = 0 // 0 is primary, 1 is supporting
 | 
				
			||||||
	for (const event of events) {
 | 
						for (const event of events) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const assert = require("assert").strict
 | 
					const assert = require("assert").strict
 | 
				
			||||||
const markdown = require("discord-markdown")
 | 
					const markdown = require("discord-markdown")
 | 
				
			||||||
 | 
					const DiscordTypes = require("discord-api-types/v10")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const passthrough = require("../../passthrough")
 | 
					const passthrough = require("../../passthrough")
 | 
				
			||||||
const { sync, db, discord } = passthrough
 | 
					const { sync, db, discord } = passthrough
 | 
				
			||||||
| 
						 | 
					@ -39,10 +40,56 @@ function getDiscordParseCallbacks(message, useHTML) {
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @param {import("discord-api-types/v10").APIMessage} message
 | 
					 * @param {import("discord-api-types/v10").APIMessage} message
 | 
				
			||||||
 * @param {import("discord-api-types/v10").APIGuild} guild
 | 
					 * @param {import("discord-api-types/v10").APIGuild} guild
 | 
				
			||||||
 | 
					 * @param {import("../../matrix/api")} api simple-as-nails dependency injection for the matrix API
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
async function messageToEvent(message, guild) {
 | 
					async function messageToEvent(message, guild, api) {
 | 
				
			||||||
	const events = []
 | 
						const events = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						   @type {{room?: boolean, user_ids?: string[]}}
 | 
				
			||||||
 | 
							We should consider the following scenarios for mentions:
 | 
				
			||||||
 | 
							1. TODO A discord user rich-replies to a matrix user with a text post
 | 
				
			||||||
 | 
								+ The matrix user needs to be m.mentioned in the text event
 | 
				
			||||||
 | 
								+ The matrix user needs to have their name/mxid/link in the text event (notification fallback)
 | 
				
			||||||
 | 
									- So prepend their `@name:` to the start of the plaintext body
 | 
				
			||||||
 | 
							2. TODO A discord user rich-replies to a matrix user with an image event only
 | 
				
			||||||
 | 
								+ The matrix user needs to be m.mentioned in the image event
 | 
				
			||||||
 | 
								+ The matrix user needs to have their name/mxid in the image event's body field, alongside the filename (notification fallback)
 | 
				
			||||||
 | 
									- So append their name to the filename body, I guess!!!
 | 
				
			||||||
 | 
							3. TODO A discord user `@`s a matrix user in the text body of their text box
 | 
				
			||||||
 | 
								+ The matrix user needs to be m.mentioned in the text event
 | 
				
			||||||
 | 
								+ No change needed to the text event content: it already has their name
 | 
				
			||||||
 | 
									- So make sure we don't do anything in this case.
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						const mentions = {}
 | 
				
			||||||
 | 
						let repliedToEventId = null
 | 
				
			||||||
 | 
						let repliedToEventRoomId = null
 | 
				
			||||||
 | 
						let repliedToEventSenderMxid = null
 | 
				
			||||||
 | 
						let repliedToEventOriginallyFromMatrix = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						function addMention(mxid) {
 | 
				
			||||||
 | 
							if (!mentions.user_ids) mentions.user_ids = []
 | 
				
			||||||
 | 
							mentions.user_ids.push(mxid)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Mentions scenarios 1 and 2, part A. i.e. translate relevant message.mentions to m.mentions
 | 
				
			||||||
 | 
						// (Still need to do scenarios 1 and 2 part B, and scenario 3.)
 | 
				
			||||||
 | 
						if (message.type === DiscordTypes.MessageType.Reply && message.message_reference?.message_id) {
 | 
				
			||||||
 | 
							const row = db.prepare("SELECT event_id, room_id, source FROM event_message INNER JOIN channel_room USING (channel_id) WHERE message_id = ? AND part = 0").get(message.message_reference.message_id)
 | 
				
			||||||
 | 
							if (row) {
 | 
				
			||||||
 | 
								repliedToEventId = row.event_id
 | 
				
			||||||
 | 
								repliedToEventRoomId = row.room_id
 | 
				
			||||||
 | 
								repliedToEventOriginallyFromMatrix = row.source === 0 // source 0 = matrix
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (repliedToEventOriginallyFromMatrix) {
 | 
				
			||||||
 | 
							// Need to figure out who sent that event...
 | 
				
			||||||
 | 
							const event = await api.getEvent(repliedToEventRoomId, repliedToEventId)
 | 
				
			||||||
 | 
							repliedToEventSenderMxid = event.sender
 | 
				
			||||||
 | 
							// Need to add the sender to m.mentions
 | 
				
			||||||
 | 
							addMention(repliedToEventSenderMxid)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Text content appears first
 | 
						// Text content appears first
 | 
				
			||||||
	if (message.content) {
 | 
						if (message.content) {
 | 
				
			||||||
		let content = message.content
 | 
							let content = message.content
 | 
				
			||||||
| 
						 | 
					@ -55,33 +102,63 @@ async function messageToEvent(message, guild) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const html = markdown.toHTML(content, {
 | 
							let html = markdown.toHTML(content, {
 | 
				
			||||||
			discordCallback: getDiscordParseCallbacks(message, true)
 | 
								discordCallback: getDiscordParseCallbacks(message, true)
 | 
				
			||||||
		}, null, null)
 | 
							}, null, null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const body = markdown.toHTML(content, {
 | 
							let body = markdown.toHTML(content, {
 | 
				
			||||||
			discordCallback: getDiscordParseCallbacks(message, false),
 | 
								discordCallback: getDiscordParseCallbacks(message, false),
 | 
				
			||||||
			discordOnly: true,
 | 
								discordOnly: true,
 | 
				
			||||||
			escapeHTML: false,
 | 
								escapeHTML: false,
 | 
				
			||||||
		}, null, null)
 | 
							}, null, null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Fallback body/formatted_body for replies
 | 
				
			||||||
 | 
							if (repliedToEventId) {
 | 
				
			||||||
 | 
								let repliedToDisplayName
 | 
				
			||||||
 | 
								let repliedToUserHtml
 | 
				
			||||||
 | 
								if (repliedToEventOriginallyFromMatrix && repliedToEventSenderMxid) {
 | 
				
			||||||
 | 
									const match = repliedToEventSenderMxid.match(/^@([^:]*)/)
 | 
				
			||||||
 | 
									assert(match)
 | 
				
			||||||
 | 
									repliedToDisplayName = match[1] || "a Matrix user" // grab the localpart as the display name, whatever
 | 
				
			||||||
 | 
									repliedToUserHtml = `<a href="https://matrix.to/#/${repliedToEventSenderMxid}">${repliedToDisplayName}</a>`
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									repliedToDisplayName = message.referenced_message?.author.global_name || message.referenced_message?.author.username || "a Discord user"
 | 
				
			||||||
 | 
									repliedToUserHtml = repliedToDisplayName
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								const repliedToContent = message.referenced_message?.content || "[Replied-to message content wasn't provided by Discord]"
 | 
				
			||||||
 | 
								const repliedToHtml = markdown.toHTML(repliedToContent, {
 | 
				
			||||||
 | 
									discordCallback: getDiscordParseCallbacks(message, true)
 | 
				
			||||||
 | 
								}, null, null)
 | 
				
			||||||
 | 
								const repliedToBody = markdown.toHTML(repliedToContent, {
 | 
				
			||||||
 | 
									discordCallback: getDiscordParseCallbacks(message, false),
 | 
				
			||||||
 | 
									discordOnly: true,
 | 
				
			||||||
 | 
									escapeHTML: false,
 | 
				
			||||||
 | 
								}, null, null)
 | 
				
			||||||
 | 
								html = `<mx-reply><blockquote><a href="https://matrix.to/#/${repliedToEventRoomId}/${repliedToEventId}">In reply to</a> ${repliedToUserHtml}`
 | 
				
			||||||
 | 
									+ `<br>${repliedToHtml}</blockquote></mx-reply>`
 | 
				
			||||||
 | 
									+ html
 | 
				
			||||||
 | 
								body = (`${repliedToDisplayName}: ` // scenario 1 part B for mentions
 | 
				
			||||||
 | 
									+ repliedToBody).split("\n").map(line => "> " + line).join("\n")
 | 
				
			||||||
 | 
									+ "\n\n" + body
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const newTextMessageEvent = {
 | 
				
			||||||
 | 
								$type: "m.room.message",
 | 
				
			||||||
 | 
								"m.mentions": mentions,
 | 
				
			||||||
 | 
								msgtype: "m.text",
 | 
				
			||||||
 | 
								body: body
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const isPlaintext = body === html
 | 
							const isPlaintext = body === html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (isPlaintext) {
 | 
							if (!isPlaintext) {
 | 
				
			||||||
			events.push({
 | 
								Object.assign(newTextMessageEvent, {
 | 
				
			||||||
				$type: "m.room.message",
 | 
					 | 
				
			||||||
				msgtype: "m.text",
 | 
					 | 
				
			||||||
				body: body
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			events.push({
 | 
					 | 
				
			||||||
				$type: "m.room.message",
 | 
					 | 
				
			||||||
				msgtype: "m.text",
 | 
					 | 
				
			||||||
				body: body,
 | 
					 | 
				
			||||||
				format: "org.matrix.custom.html",
 | 
									format: "org.matrix.custom.html",
 | 
				
			||||||
				formatted_body: html
 | 
									formatted_body: html
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							events.push(newTextMessageEvent)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Then attachments
 | 
						// Then attachments
 | 
				
			||||||
| 
						 | 
					@ -90,6 +167,7 @@ async function messageToEvent(message, guild) {
 | 
				
			||||||
		if (attachment.content_type?.startsWith("image/") && attachment.width && attachment.height) {
 | 
							if (attachment.content_type?.startsWith("image/") && attachment.width && attachment.height) {
 | 
				
			||||||
			return {
 | 
								return {
 | 
				
			||||||
				$type: "m.room.message",
 | 
									$type: "m.room.message",
 | 
				
			||||||
 | 
									"m.mentions": mentions,
 | 
				
			||||||
				msgtype: "m.image",
 | 
									msgtype: "m.image",
 | 
				
			||||||
				url: await file.uploadDiscordFileToMxc(attachment.url),
 | 
									url: await file.uploadDiscordFileToMxc(attachment.url),
 | 
				
			||||||
				external_url: attachment.url,
 | 
									external_url: attachment.url,
 | 
				
			||||||
| 
						 | 
					@ -105,6 +183,7 @@ async function messageToEvent(message, guild) {
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			return {
 | 
								return {
 | 
				
			||||||
				$type: "m.room.message",
 | 
									$type: "m.room.message",
 | 
				
			||||||
 | 
									"m.mentions": mentions,
 | 
				
			||||||
				msgtype: "m.text",
 | 
									msgtype: "m.text",
 | 
				
			||||||
				body: "Unsupported attachment:\n" + JSON.stringify(attachment, null, 2)
 | 
									body: "Unsupported attachment:\n" + JSON.stringify(attachment, null, 2)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -122,6 +201,7 @@ async function messageToEvent(message, guild) {
 | 
				
			||||||
				if (sticker && sticker.description) body += ` - ${sticker.description}`
 | 
									if (sticker && sticker.description) body += ` - ${sticker.description}`
 | 
				
			||||||
				return {
 | 
									return {
 | 
				
			||||||
					$type: "m.sticker",
 | 
										$type: "m.sticker",
 | 
				
			||||||
 | 
										"m.mentions": mentions,
 | 
				
			||||||
					body,
 | 
										body,
 | 
				
			||||||
					info: {
 | 
										info: {
 | 
				
			||||||
						mimetype: format.mime
 | 
											mimetype: format.mime
 | 
				
			||||||
| 
						 | 
					@ -131,6 +211,7 @@ async function messageToEvent(message, guild) {
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return {
 | 
									return {
 | 
				
			||||||
					$type: "m.room.message",
 | 
										$type: "m.room.message",
 | 
				
			||||||
 | 
										"m.mentions": mentions,
 | 
				
			||||||
					msgtype: "m.text",
 | 
										msgtype: "m.text",
 | 
				
			||||||
					body: "Unsupported sticker format. Name: " + stickerItem.name
 | 
										body: "Unsupported sticker format. Name: " + stickerItem.name
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					@ -139,6 +220,17 @@ async function messageToEvent(message, guild) {
 | 
				
			||||||
		events.push(...stickerEvents)
 | 
							events.push(...stickerEvents)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Rich replies
 | 
				
			||||||
 | 
						if (repliedToEventId) {
 | 
				
			||||||
 | 
							Object.assign(events[0], {
 | 
				
			||||||
 | 
								"m.relates_to": {
 | 
				
			||||||
 | 
									"m.in_reply_to": {
 | 
				
			||||||
 | 
										event_id: repliedToEventId
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return events
 | 
						return events
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,39 @@
 | 
				
			||||||
const {test} = require("supertape")
 | 
					const {test} = require("supertape")
 | 
				
			||||||
const {messageToEvent} = require("./message-to-event")
 | 
					const {messageToEvent} = require("./message-to-event")
 | 
				
			||||||
const data = require("../../test/data")
 | 
					const data = require("../../test/data")
 | 
				
			||||||
 | 
					const Ty = require("../../types")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {string} roomID
 | 
				
			||||||
 | 
					 * @param {string} eventID
 | 
				
			||||||
 | 
					 * @returns {(roomID: string, eventID: string) => Promise<Ty.Event.Outer<Ty.Event.M_Room_Message>>}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function mockGetEvent(t, roomID_in, eventID_in, outer) {
 | 
				
			||||||
 | 
						return async function(roomID, eventID) {
 | 
				
			||||||
 | 
							t.equal(roomID, roomID_in)
 | 
				
			||||||
 | 
							t.equal(eventID, eventID_in)
 | 
				
			||||||
 | 
							return new Promise(resolve => {
 | 
				
			||||||
 | 
								setTimeout(() => {
 | 
				
			||||||
 | 
									resolve({
 | 
				
			||||||
 | 
										event_id: eventID_in,
 | 
				
			||||||
 | 
										room_id: roomID_in,
 | 
				
			||||||
 | 
										origin_server_ts: 1680000000000,
 | 
				
			||||||
 | 
										unsigned: {
 | 
				
			||||||
 | 
											age: 2245,
 | 
				
			||||||
 | 
											transaction_id: "$local.whatever"
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										...outer
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("message2event: simple plaintext", async t => {
 | 
					test("message2event: simple plaintext", async t => {
 | 
				
			||||||
	const events = await messageToEvent(data.message.simple_plaintext, data.guild.general)
 | 
						const events = await messageToEvent(data.message.simple_plaintext, data.guild.general)
 | 
				
			||||||
	t.deepEqual(events, [{
 | 
						t.deepEqual(events, [{
 | 
				
			||||||
		$type: "m.room.message",
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
		msgtype: "m.text",
 | 
							msgtype: "m.text",
 | 
				
			||||||
		body: "ayy lmao"
 | 
							body: "ayy lmao"
 | 
				
			||||||
	}])
 | 
						}])
 | 
				
			||||||
| 
						 | 
					@ -15,6 +43,7 @@ test("message2event: simple user mention", async t => {
 | 
				
			||||||
	const events = await messageToEvent(data.message.simple_user_mention, data.guild.general)
 | 
						const events = await messageToEvent(data.message.simple_user_mention, data.guild.general)
 | 
				
			||||||
	t.deepEqual(events, [{
 | 
						t.deepEqual(events, [{
 | 
				
			||||||
		$type: "m.room.message",
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
		msgtype: "m.text",
 | 
							msgtype: "m.text",
 | 
				
			||||||
		body: "@crunch god: Tell me about Phil, renowned martial arts master and creator of the Chin Trick",
 | 
							body: "@crunch god: Tell me about Phil, renowned martial arts master and creator of the Chin Trick",
 | 
				
			||||||
		format: "org.matrix.custom.html",
 | 
							format: "org.matrix.custom.html",
 | 
				
			||||||
| 
						 | 
					@ -26,6 +55,7 @@ test("message2event: simple room mention", async t => {
 | 
				
			||||||
	const events = await messageToEvent(data.message.simple_room_mention, data.guild.general)
 | 
						const events = await messageToEvent(data.message.simple_room_mention, data.guild.general)
 | 
				
			||||||
	t.deepEqual(events, [{
 | 
						t.deepEqual(events, [{
 | 
				
			||||||
		$type: "m.room.message",
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
		msgtype: "m.text",
 | 
							msgtype: "m.text",
 | 
				
			||||||
		body: "#main",
 | 
							body: "#main",
 | 
				
			||||||
		format: "org.matrix.custom.html",
 | 
							format: "org.matrix.custom.html",
 | 
				
			||||||
| 
						 | 
					@ -37,6 +67,7 @@ test("message2event: simple message link", async t => {
 | 
				
			||||||
	const events = await messageToEvent(data.message.simple_message_link, data.guild.general)
 | 
						const events = await messageToEvent(data.message.simple_message_link, data.guild.general)
 | 
				
			||||||
	t.deepEqual(events, [{
 | 
						t.deepEqual(events, [{
 | 
				
			||||||
		$type: "m.room.message",
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
		msgtype: "m.text",
 | 
							msgtype: "m.text",
 | 
				
			||||||
		body: "https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$X16nfVks1wsrhq4E9SSLiqrf2N8KD0erD0scZG7U5xg",
 | 
							body: "https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$X16nfVks1wsrhq4E9SSLiqrf2N8KD0erD0scZG7U5xg",
 | 
				
			||||||
		format: "org.matrix.custom.html",
 | 
							format: "org.matrix.custom.html",
 | 
				
			||||||
| 
						 | 
					@ -48,6 +79,7 @@ test("message2event: attachment with no content", async t => {
 | 
				
			||||||
	const events = await messageToEvent(data.message.attachment_no_content, data.guild.general)
 | 
						const events = await messageToEvent(data.message.attachment_no_content, data.guild.general)
 | 
				
			||||||
	t.deepEqual(events, [{
 | 
						t.deepEqual(events, [{
 | 
				
			||||||
		$type: "m.room.message",
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
		msgtype: "m.image",
 | 
							msgtype: "m.image",
 | 
				
			||||||
		url: "mxc://cadence.moe/qXoZktDqNtEGuOCZEADAMvhM",
 | 
							url: "mxc://cadence.moe/qXoZktDqNtEGuOCZEADAMvhM",
 | 
				
			||||||
		body: "image.png",
 | 
							body: "image.png",
 | 
				
			||||||
| 
						 | 
					@ -65,10 +97,12 @@ test("message2event: stickers", async t => {
 | 
				
			||||||
	const events = await messageToEvent(data.message.sticker, data.guild.general)
 | 
						const events = await messageToEvent(data.message.sticker, data.guild.general)
 | 
				
			||||||
	t.deepEqual(events, [{
 | 
						t.deepEqual(events, [{
 | 
				
			||||||
		$type: "m.room.message",
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
		msgtype: "m.text",
 | 
							msgtype: "m.text",
 | 
				
			||||||
		body: "can have attachments too"
 | 
							body: "can have attachments too"
 | 
				
			||||||
	}, {
 | 
						}, {
 | 
				
			||||||
		$type: "m.room.message",
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
		msgtype: "m.image",
 | 
							msgtype: "m.image",
 | 
				
			||||||
		url: "mxc://cadence.moe/ZDCNYnkPszxGKgObUIFmvjus",
 | 
							url: "mxc://cadence.moe/ZDCNYnkPszxGKgObUIFmvjus",
 | 
				
			||||||
		body: "image.png",
 | 
							body: "image.png",
 | 
				
			||||||
| 
						 | 
					@ -81,6 +115,7 @@ test("message2event: stickers", async t => {
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}, {
 | 
						}, {
 | 
				
			||||||
		$type: "m.sticker",
 | 
							$type: "m.sticker",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
		body: "pomu puff - damn that tiny lil bitch really chuffing. puffing that fat ass dart",
 | 
							body: "pomu puff - damn that tiny lil bitch really chuffing. puffing that fat ass dart",
 | 
				
			||||||
		info: {
 | 
							info: {
 | 
				
			||||||
			mimetype: "image/png"
 | 
								mimetype: "image/png"
 | 
				
			||||||
| 
						 | 
					@ -90,3 +125,94 @@ test("message2event: stickers", async t => {
 | 
				
			||||||
		url: "mxc://cadence.moe/UuUaLwXhkxFRwwWCXipDlBHn"
 | 
							url: "mxc://cadence.moe/UuUaLwXhkxFRwwWCXipDlBHn"
 | 
				
			||||||
	}])
 | 
						}])
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("message2event: skull webp attachment with content", async t => {
 | 
				
			||||||
 | 
						const events = await messageToEvent(data.message.skull_webp_attachment_with_content, data.guild.general)
 | 
				
			||||||
 | 
						t.deepEqual(events, [{
 | 
				
			||||||
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
 | 
							msgtype: "m.text",
 | 
				
			||||||
 | 
							body: "Image"
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
 | 
							msgtype: "m.image",
 | 
				
			||||||
 | 
							body: "skull.webp",
 | 
				
			||||||
 | 
							info: {
 | 
				
			||||||
 | 
								w: 1200,
 | 
				
			||||||
 | 
								h: 628,
 | 
				
			||||||
 | 
								mimetype: "image/webp",
 | 
				
			||||||
 | 
								size: 74290
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							external_url: "https://cdn.discordapp.com/attachments/112760669178241024/1128084747910918195/skull.webp",
 | 
				
			||||||
 | 
							url: "mxc://cadence.moe/sDxWmDErBhYBxtDcJQgBETes"
 | 
				
			||||||
 | 
						}])
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("message2event: reply to skull webp attachment with content", async t => {
 | 
				
			||||||
 | 
						const events = await messageToEvent(data.message.reply_to_skull_webp_attachment_with_content, data.guild.general)
 | 
				
			||||||
 | 
						t.deepEqual(events, [{
 | 
				
			||||||
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.relates_to": {
 | 
				
			||||||
 | 
								"m.in_reply_to": {
 | 
				
			||||||
 | 
									event_id: "$oLyUTyZ_7e_SUzGNWZKz880ll9amLZvXGbArJCKai2Q"
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
 | 
							msgtype: "m.text",
 | 
				
			||||||
 | 
							body: "> Extremity: Image\n\nReply",
 | 
				
			||||||
 | 
							format: "org.matrix.custom.html",
 | 
				
			||||||
 | 
							formatted_body:
 | 
				
			||||||
 | 
								'<mx-reply><blockquote><a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$oLyUTyZ_7e_SUzGNWZKz880ll9amLZvXGbArJCKai2Q">In reply to</a> Extremity'
 | 
				
			||||||
 | 
								+ '<br>Image</blockquote></mx-reply>'
 | 
				
			||||||
 | 
								+ 'Reply'
 | 
				
			||||||
 | 
						}, {
 | 
				
			||||||
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.mentions": {},
 | 
				
			||||||
 | 
							msgtype: "m.image",
 | 
				
			||||||
 | 
							body: "RDT_20230704_0936184915846675925224905.jpg",
 | 
				
			||||||
 | 
							info: {
 | 
				
			||||||
 | 
								w: 2048,
 | 
				
			||||||
 | 
								h: 1536,
 | 
				
			||||||
 | 
								mimetype: "image/jpeg",
 | 
				
			||||||
 | 
								size: 85906
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							external_url: "https://cdn.discordapp.com/attachments/112760669178241024/1128084851023675515/RDT_20230704_0936184915846675925224905.jpg",
 | 
				
			||||||
 | 
							url: "mxc://cadence.moe/WlAbFSiNRIHPDEwKdyPeGywa"
 | 
				
			||||||
 | 
						}])
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("message2event: simple reply to matrix user", async t => {
 | 
				
			||||||
 | 
						const events = await messageToEvent(data.message.simple_reply_to_matrix_user, data.guild.general, {
 | 
				
			||||||
 | 
							getEvent: mockGetEvent(t, "!kLRqKKUQXcibIMtOpl:cadence.moe", "$Ij3qo7NxMA4VPexlAiIx2CB9JbsiGhJeyt-2OvkAUe4", {
 | 
				
			||||||
 | 
								type: "m.room.message",
 | 
				
			||||||
 | 
								content: {
 | 
				
			||||||
 | 
									msgtype: "m.text",
 | 
				
			||||||
 | 
									body: "so can you reply to my webhook uwu"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								sender: "@cadence:cadence.moe"
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						t.deepEqual(events, [{
 | 
				
			||||||
 | 
							$type: "m.room.message",
 | 
				
			||||||
 | 
							"m.relates_to": {
 | 
				
			||||||
 | 
								"m.in_reply_to": {
 | 
				
			||||||
 | 
									event_id: "$Ij3qo7NxMA4VPexlAiIx2CB9JbsiGhJeyt-2OvkAUe4"
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"m.mentions": {
 | 
				
			||||||
 | 
								user_ids: [
 | 
				
			||||||
 | 
									"@cadence:cadence.moe"
 | 
				
			||||||
 | 
								]
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							msgtype: "m.text",
 | 
				
			||||||
 | 
							body: "> cadence: so can you reply to my webhook uwu\n\nReply",
 | 
				
			||||||
 | 
							format: "org.matrix.custom.html",
 | 
				
			||||||
 | 
							formatted_body:
 | 
				
			||||||
 | 
								'<mx-reply><blockquote><a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$Ij3qo7NxMA4VPexlAiIx2CB9JbsiGhJeyt-2OvkAUe4">In reply to</a> <a href="https://matrix.to/#/@cadence:cadence.moe">cadence</a>'
 | 
				
			||||||
 | 
								+ '<br>so can you reply to my webhook uwu</blockquote></mx-reply>'
 | 
				
			||||||
 | 
								+ 'Reply'
 | 
				
			||||||
 | 
						}])
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: read "edits of replies" in the spec
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,6 +65,17 @@ async function leaveRoom(roomID, mxid) {
 | 
				
			||||||
   await mreq.mreq("POST", path(`/client/v3/rooms/${roomID}/leave`, mxid), {})
 | 
					   await mreq.mreq("POST", path(`/client/v3/rooms/${roomID}/leave`, mxid), {})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {string} roomID
 | 
				
			||||||
 | 
					 * @param {string} eventID
 | 
				
			||||||
 | 
					 * @template T
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					async function getEvent(roomID, eventID) {
 | 
				
			||||||
 | 
					   /** @type {Ty.Event.Outer<T>} */
 | 
				
			||||||
 | 
					   const root = await mreq.mreq("GET", `/client/v3/rooms/${roomID}/event/${eventID}`)
 | 
				
			||||||
 | 
					   return root
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @param {string} roomID
 | 
					 * @param {string} roomID
 | 
				
			||||||
 * @returns {Promise<Ty.Event.BaseStateEvent[]>}
 | 
					 * @returns {Promise<Ty.Event.BaseStateEvent[]>}
 | 
				
			||||||
| 
						 | 
					@ -73,6 +84,15 @@ function getAllState(roomID) {
 | 
				
			||||||
   return mreq.mreq("GET", `/client/v3/rooms/${roomID}/state`)
 | 
					   return mreq.mreq("GET", `/client/v3/rooms/${roomID}/state`)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * "Any of the AS's users must be in the room. This API is primarily for Application Services and should be faster to respond than /members as it can be implemented more efficiently on the server."
 | 
				
			||||||
 | 
					 * @param {string} roomID
 | 
				
			||||||
 | 
					 * @returns {Promise<{joined: {[mxid: string]: Ty.R.RoomMember}}>}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function getJoinedMembers(roomID) {
 | 
				
			||||||
 | 
					   return mreq.mreq("GET", `/client/v3/rooms/${roomID}/joined_members`)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @param {string} roomID
 | 
					 * @param {string} roomID
 | 
				
			||||||
 * @param {string} type
 | 
					 * @param {string} type
 | 
				
			||||||
| 
						 | 
					@ -114,7 +134,9 @@ module.exports.createRoom = createRoom
 | 
				
			||||||
module.exports.joinRoom = joinRoom
 | 
					module.exports.joinRoom = joinRoom
 | 
				
			||||||
module.exports.inviteToRoom = inviteToRoom
 | 
					module.exports.inviteToRoom = inviteToRoom
 | 
				
			||||||
module.exports.leaveRoom = leaveRoom
 | 
					module.exports.leaveRoom = leaveRoom
 | 
				
			||||||
 | 
					module.exports.getEvent = getEvent
 | 
				
			||||||
module.exports.getAllState = getAllState
 | 
					module.exports.getAllState = getAllState
 | 
				
			||||||
 | 
					module.exports.getJoinedMembers = getJoinedMembers
 | 
				
			||||||
module.exports.sendState = sendState
 | 
					module.exports.sendState = sendState
 | 
				
			||||||
module.exports.sendEvent = sendEvent
 | 
					module.exports.sendEvent = sendEvent
 | 
				
			||||||
module.exports.profileSetDisplayname = profileSetDisplayname
 | 
					module.exports.profileSetDisplayname = profileSetDisplayname
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,6 @@
 | 
				
			||||||
    "tap-dot": "github:cloudrac3r/tap-dot#223a4e67a6f7daf015506a12a7af74605f06c7f4"
 | 
					    "tap-dot": "github:cloudrac3r/tap-dot#223a4e67a6f7daf015506a12a7af74605f06c7f4"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "test": "cross-env FORCE_COLOR=true supertape --format tap test/test.js | tap-dot"
 | 
					    "test": "cross-env FORCE_COLOR=true supertape --no-check-assertions-count --format tap test/test.js | tap-dot"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										428
									
								
								test/data.js
									
										
									
									
									
								
							
							
						
						
									
										428
									
								
								test/data.js
									
										
									
									
									
								
							| 
						 | 
					@ -423,6 +423,434 @@ module.exports = {
 | 
				
			||||||
			flags: 0,
 | 
								flags: 0,
 | 
				
			||||||
			components: []
 | 
								components: []
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							skull_webp_attachment_with_content: {
 | 
				
			||||||
 | 
								type: 0,
 | 
				
			||||||
 | 
								tts: false,
 | 
				
			||||||
 | 
								timestamp: "2023-07-10T22:06:02.805000+00:00",
 | 
				
			||||||
 | 
								referenced_message: null,
 | 
				
			||||||
 | 
								pinned: false,
 | 
				
			||||||
 | 
								nonce: "1128084721398448128",
 | 
				
			||||||
 | 
								mentions: [],
 | 
				
			||||||
 | 
								mention_roles: [],
 | 
				
			||||||
 | 
								mention_everyone: false,
 | 
				
			||||||
 | 
								member: {
 | 
				
			||||||
 | 
									roles: [
 | 
				
			||||||
 | 
										"112767366235959296",
 | 
				
			||||||
 | 
										"118924814567211009",
 | 
				
			||||||
 | 
										"199995902742626304",
 | 
				
			||||||
 | 
										"204427286542417920",
 | 
				
			||||||
 | 
										"222168467627835392",
 | 
				
			||||||
 | 
										"271173313575780353",
 | 
				
			||||||
 | 
										"392141548932038658",
 | 
				
			||||||
 | 
										"1040735082610167858",
 | 
				
			||||||
 | 
										"372954403902193689",
 | 
				
			||||||
 | 
										"1124134606514442300",
 | 
				
			||||||
 | 
										"585531096071012409"
 | 
				
			||||||
 | 
									],
 | 
				
			||||||
 | 
									premium_since: "2022-04-20T21:11:14.016000+00:00",
 | 
				
			||||||
 | 
									pending: false,
 | 
				
			||||||
 | 
									nick: "Tap to add a nickname",
 | 
				
			||||||
 | 
									mute: false,
 | 
				
			||||||
 | 
									joined_at: "2022-04-20T20:16:02.828000+00:00",
 | 
				
			||||||
 | 
									flags: 0,
 | 
				
			||||||
 | 
									deaf: false,
 | 
				
			||||||
 | 
									communication_disabled_until: null,
 | 
				
			||||||
 | 
									avatar: "a_4ea72c7b058ad848c9d9d35479fac26e"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								id: "1128084748338741392",
 | 
				
			||||||
 | 
								flags: 0,
 | 
				
			||||||
 | 
								embeds: [],
 | 
				
			||||||
 | 
								edited_timestamp: null,
 | 
				
			||||||
 | 
								content: "Image",
 | 
				
			||||||
 | 
								components: [],
 | 
				
			||||||
 | 
								channel_id: "112760669178241024",
 | 
				
			||||||
 | 
								author: {
 | 
				
			||||||
 | 
									username: "extremity",
 | 
				
			||||||
 | 
									public_flags: 768,
 | 
				
			||||||
 | 
									id: "114147806469554185",
 | 
				
			||||||
 | 
									global_name: "Extremity",
 | 
				
			||||||
 | 
									discriminator: "0",
 | 
				
			||||||
 | 
									avatar_decoration: null,
 | 
				
			||||||
 | 
									avatar: "6628aaf6b27219c36e2d3b5cfd6d0ee6"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								attachments: [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										width: 1200,
 | 
				
			||||||
 | 
										url: "https://cdn.discordapp.com/attachments/112760669178241024/1128084747910918195/skull.webp",
 | 
				
			||||||
 | 
										size: 74290,
 | 
				
			||||||
 | 
										proxy_url: "https://media.discordapp.net/attachments/112760669178241024/1128084747910918195/skull.webp",
 | 
				
			||||||
 | 
										id: "1128084747910918195",
 | 
				
			||||||
 | 
										height: 628,
 | 
				
			||||||
 | 
										filename: "skull.webp",
 | 
				
			||||||
 | 
										content_type: "image/webp"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								],
 | 
				
			||||||
 | 
								guild_id: "112760669178241024"
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							reply_to_skull_webp_attachment_with_content: {
 | 
				
			||||||
 | 
								type: 19,
 | 
				
			||||||
 | 
								tts: false,
 | 
				
			||||||
 | 
								timestamp: "2023-07-10T22:06:27.348000+00:00",
 | 
				
			||||||
 | 
								referenced_message: {
 | 
				
			||||||
 | 
									type: 0,
 | 
				
			||||||
 | 
									tts: false,
 | 
				
			||||||
 | 
									timestamp: "2023-07-10T22:06:02.805000+00:00",
 | 
				
			||||||
 | 
									pinned: false,
 | 
				
			||||||
 | 
									mentions: [],
 | 
				
			||||||
 | 
									mention_roles: [],
 | 
				
			||||||
 | 
									mention_everyone: false,
 | 
				
			||||||
 | 
									id: "1128084748338741392",
 | 
				
			||||||
 | 
									flags: 0,
 | 
				
			||||||
 | 
									embeds: [],
 | 
				
			||||||
 | 
									edited_timestamp: null,
 | 
				
			||||||
 | 
									content: "Image",
 | 
				
			||||||
 | 
									components: [],
 | 
				
			||||||
 | 
									channel_id: "112760669178241024",
 | 
				
			||||||
 | 
									author: {
 | 
				
			||||||
 | 
										username: "extremity",
 | 
				
			||||||
 | 
										public_flags: 768,
 | 
				
			||||||
 | 
										id: "114147806469554185",
 | 
				
			||||||
 | 
										global_name: "Extremity",
 | 
				
			||||||
 | 
										discriminator: "0",
 | 
				
			||||||
 | 
										avatar_decoration: null,
 | 
				
			||||||
 | 
										avatar: "6628aaf6b27219c36e2d3b5cfd6d0ee6"
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									attachments: [
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											width: 1200,
 | 
				
			||||||
 | 
											url: "https://cdn.discordapp.com/attachments/112760669178241024/1128084747910918195/skull.webp",
 | 
				
			||||||
 | 
											size: 74290,
 | 
				
			||||||
 | 
											proxy_url: "https://media.discordapp.net/attachments/112760669178241024/1128084747910918195/skull.webp",
 | 
				
			||||||
 | 
											id: "1128084747910918195",
 | 
				
			||||||
 | 
											height: 628,
 | 
				
			||||||
 | 
											filename: "skull.webp",
 | 
				
			||||||
 | 
											content_type: "image/webp"
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									]
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								pinned: false,
 | 
				
			||||||
 | 
								nonce: "1128084845403045888",
 | 
				
			||||||
 | 
								message_reference: {
 | 
				
			||||||
 | 
									message_id: "1128084748338741392",
 | 
				
			||||||
 | 
									guild_id: "112760669178241024",
 | 
				
			||||||
 | 
									channel_id: "112760669178241024"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								mentions: [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										username: "extremity",
 | 
				
			||||||
 | 
										public_flags: 768,
 | 
				
			||||||
 | 
										member: {
 | 
				
			||||||
 | 
											roles: [
 | 
				
			||||||
 | 
												"112767366235959296",
 | 
				
			||||||
 | 
												"118924814567211009",
 | 
				
			||||||
 | 
												"199995902742626304",
 | 
				
			||||||
 | 
												"204427286542417920",
 | 
				
			||||||
 | 
												"222168467627835392",
 | 
				
			||||||
 | 
												"271173313575780353",
 | 
				
			||||||
 | 
												"392141548932038658",
 | 
				
			||||||
 | 
												"1040735082610167858",
 | 
				
			||||||
 | 
												"372954403902193689",
 | 
				
			||||||
 | 
												"1124134606514442300",
 | 
				
			||||||
 | 
												"585531096071012409"
 | 
				
			||||||
 | 
											],
 | 
				
			||||||
 | 
											premium_since: "2022-04-20T21:11:14.016000+00:00",
 | 
				
			||||||
 | 
											pending: false,
 | 
				
			||||||
 | 
											nick: "Tap to add a nickname",
 | 
				
			||||||
 | 
											mute: false,
 | 
				
			||||||
 | 
											joined_at: "2022-04-20T20:16:02.828000+00:00",
 | 
				
			||||||
 | 
											flags: 0,
 | 
				
			||||||
 | 
											deaf: false,
 | 
				
			||||||
 | 
											communication_disabled_until: null,
 | 
				
			||||||
 | 
											avatar: "a_4ea72c7b058ad848c9d9d35479fac26e"
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										id: "114147806469554185",
 | 
				
			||||||
 | 
										global_name: "Extremity",
 | 
				
			||||||
 | 
										discriminator: "0",
 | 
				
			||||||
 | 
										avatar_decoration: null,
 | 
				
			||||||
 | 
										avatar: "6628aaf6b27219c36e2d3b5cfd6d0ee6"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								],
 | 
				
			||||||
 | 
								mention_roles: [],
 | 
				
			||||||
 | 
								mention_everyone: false,
 | 
				
			||||||
 | 
								member: {
 | 
				
			||||||
 | 
									roles: [
 | 
				
			||||||
 | 
										"112767366235959296",
 | 
				
			||||||
 | 
										"118924814567211009",
 | 
				
			||||||
 | 
										"199995902742626304",
 | 
				
			||||||
 | 
										"204427286542417920",
 | 
				
			||||||
 | 
										"222168467627835392",
 | 
				
			||||||
 | 
										"271173313575780353",
 | 
				
			||||||
 | 
										"392141548932038658",
 | 
				
			||||||
 | 
										"1040735082610167858",
 | 
				
			||||||
 | 
										"372954403902193689",
 | 
				
			||||||
 | 
										"1124134606514442300",
 | 
				
			||||||
 | 
										"585531096071012409"
 | 
				
			||||||
 | 
									],
 | 
				
			||||||
 | 
									premium_since: "2022-04-20T21:11:14.016000+00:00",
 | 
				
			||||||
 | 
									pending: false,
 | 
				
			||||||
 | 
									nick: "Tap to add a nickname",
 | 
				
			||||||
 | 
									mute: false,
 | 
				
			||||||
 | 
									joined_at: "2022-04-20T20:16:02.828000+00:00",
 | 
				
			||||||
 | 
									flags: 0,
 | 
				
			||||||
 | 
									deaf: false,
 | 
				
			||||||
 | 
									communication_disabled_until: null,
 | 
				
			||||||
 | 
									avatar: "a_4ea72c7b058ad848c9d9d35479fac26e"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								id: "1128084851279536279",
 | 
				
			||||||
 | 
								flags: 0,
 | 
				
			||||||
 | 
								embeds: [],
 | 
				
			||||||
 | 
								edited_timestamp: null,
 | 
				
			||||||
 | 
								content: "Reply",
 | 
				
			||||||
 | 
								components: [],
 | 
				
			||||||
 | 
								channel_id: "112760669178241024",
 | 
				
			||||||
 | 
								author: {
 | 
				
			||||||
 | 
									username: "extremity",
 | 
				
			||||||
 | 
									public_flags: 768,
 | 
				
			||||||
 | 
									id: "114147806469554185",
 | 
				
			||||||
 | 
									global_name: "Extremity",
 | 
				
			||||||
 | 
									discriminator: "0",
 | 
				
			||||||
 | 
									avatar_decoration: null,
 | 
				
			||||||
 | 
									avatar: "6628aaf6b27219c36e2d3b5cfd6d0ee6"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								attachments: [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										width: 2048,
 | 
				
			||||||
 | 
										url: "https://cdn.discordapp.com/attachments/112760669178241024/1128084851023675515/RDT_20230704_0936184915846675925224905.jpg",
 | 
				
			||||||
 | 
										size: 85906,
 | 
				
			||||||
 | 
										proxy_url: "https://media.discordapp.net/attachments/112760669178241024/1128084851023675515/RDT_20230704_0936184915846675925224905.jpg",
 | 
				
			||||||
 | 
										id: "1128084851023675515",
 | 
				
			||||||
 | 
										height: 1536,
 | 
				
			||||||
 | 
										filename: "RDT_20230704_0936184915846675925224905.jpg",
 | 
				
			||||||
 | 
										content_type: "image/jpeg"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								],
 | 
				
			||||||
 | 
								guild_id: "112760669178241024"
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							simple_reply_to_matrix_user: {
 | 
				
			||||||
 | 
								type: 19,
 | 
				
			||||||
 | 
								tts: false,
 | 
				
			||||||
 | 
								timestamp: "2023-07-11T00:19:04.358000+00:00",
 | 
				
			||||||
 | 
								referenced_message: {
 | 
				
			||||||
 | 
									webhook_id: "703458020193206272",
 | 
				
			||||||
 | 
									type: 0,
 | 
				
			||||||
 | 
									tts: false,
 | 
				
			||||||
 | 
									timestamp: "2023-07-11T00:18:52.856000+00:00",
 | 
				
			||||||
 | 
									pinned: false,
 | 
				
			||||||
 | 
									mentions: [],
 | 
				
			||||||
 | 
									mention_roles: [],
 | 
				
			||||||
 | 
									mention_everyone: false,
 | 
				
			||||||
 | 
									id: "1128118177155526666",
 | 
				
			||||||
 | 
									flags: 0,
 | 
				
			||||||
 | 
									embeds: [],
 | 
				
			||||||
 | 
									edited_timestamp: null,
 | 
				
			||||||
 | 
									content: "so can you reply to my webhook uwu",
 | 
				
			||||||
 | 
									components: [],
 | 
				
			||||||
 | 
									channel_id: "112760669178241024",
 | 
				
			||||||
 | 
									author: {
 | 
				
			||||||
 | 
										username: "cadence",
 | 
				
			||||||
 | 
										id: "703458020193206272",
 | 
				
			||||||
 | 
										discriminator: "0000",
 | 
				
			||||||
 | 
										bot: true,
 | 
				
			||||||
 | 
										avatar: "ea5413d310c85eb9edaa9db865e80155"
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									attachments: [],
 | 
				
			||||||
 | 
									application_id: "684280192553844747"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								pinned: false,
 | 
				
			||||||
 | 
								nonce: "1128118222315323392",
 | 
				
			||||||
 | 
								message_reference: {
 | 
				
			||||||
 | 
									message_id: "1128118177155526666",
 | 
				
			||||||
 | 
									guild_id: "112760669178241024",
 | 
				
			||||||
 | 
									channel_id: "112760669178241024"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								mentions: [],
 | 
				
			||||||
 | 
								mention_roles: [],
 | 
				
			||||||
 | 
								mention_everyone: false,
 | 
				
			||||||
 | 
								member: {
 | 
				
			||||||
 | 
									roles: [
 | 
				
			||||||
 | 
										"112767366235959296",  "118924814567211009",
 | 
				
			||||||
 | 
										"204427286542417920",  "199995902742626304",
 | 
				
			||||||
 | 
										"222168467627835392",  "238028326281805825",
 | 
				
			||||||
 | 
										"259806643414499328",  "265239342648131584",
 | 
				
			||||||
 | 
										"271173313575780353",  "287733611912757249",
 | 
				
			||||||
 | 
										"225744901915148298",  "305775031223320577",
 | 
				
			||||||
 | 
										"318243902521868288",  "348651574924541953",
 | 
				
			||||||
 | 
										"349185088157777920",  "378402925128712193",
 | 
				
			||||||
 | 
										"392141548932038658",  "393912152173576203",
 | 
				
			||||||
 | 
										"482860581670486028",  "495384759074160642",
 | 
				
			||||||
 | 
										"638988388740890635",  "373336013109461013",
 | 
				
			||||||
 | 
										"530220455085473813",  "454567553738473472",
 | 
				
			||||||
 | 
										"790724320824655873",  "1123518980456452097",
 | 
				
			||||||
 | 
										"1040735082610167858", "695946570482450442",
 | 
				
			||||||
 | 
										"1123460940935991296", "849737964090556488"
 | 
				
			||||||
 | 
									],
 | 
				
			||||||
 | 
									premium_since: null,
 | 
				
			||||||
 | 
									pending: false,
 | 
				
			||||||
 | 
									nick: null,
 | 
				
			||||||
 | 
									mute: false,
 | 
				
			||||||
 | 
									joined_at: "2015-11-11T09:55:40.321000+00:00",
 | 
				
			||||||
 | 
									flags: 0,
 | 
				
			||||||
 | 
									deaf: false,
 | 
				
			||||||
 | 
									communication_disabled_until: null,
 | 
				
			||||||
 | 
									avatar: null
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								id: "1128118225398407228",
 | 
				
			||||||
 | 
								flags: 0,
 | 
				
			||||||
 | 
								embeds: [],
 | 
				
			||||||
 | 
								edited_timestamp: null,
 | 
				
			||||||
 | 
								content: "Reply",
 | 
				
			||||||
 | 
								components: [],
 | 
				
			||||||
 | 
								channel_id: "112760669178241024",
 | 
				
			||||||
 | 
								author: {
 | 
				
			||||||
 | 
									username: "kumaccino",
 | 
				
			||||||
 | 
									public_flags: 128,
 | 
				
			||||||
 | 
									id: "113340068197859328",
 | 
				
			||||||
 | 
									global_name: "kumaccino",
 | 
				
			||||||
 | 
									discriminator: "0",
 | 
				
			||||||
 | 
									avatar_decoration: null,
 | 
				
			||||||
 | 
									avatar: "b48302623a12bc7c59a71328f72ccb39"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								attachments: [],
 | 
				
			||||||
 | 
								guild_id: "112760669178241024"
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							edit_of_reply_to_skull_webp_attachment_with_content: {
 | 
				
			||||||
 | 
								type: 19,
 | 
				
			||||||
 | 
								tts: false,
 | 
				
			||||||
 | 
								timestamp: "2023-07-10T22:06:27.348000+00:00",
 | 
				
			||||||
 | 
								referenced_message: {
 | 
				
			||||||
 | 
									type: 0,
 | 
				
			||||||
 | 
									tts: false,
 | 
				
			||||||
 | 
									timestamp: "2023-07-10T22:06:02.805000+00:00",
 | 
				
			||||||
 | 
									pinned: false,
 | 
				
			||||||
 | 
									mentions: [],
 | 
				
			||||||
 | 
									mention_roles: [],
 | 
				
			||||||
 | 
									mention_everyone: false,
 | 
				
			||||||
 | 
									id: "1128084748338741392",
 | 
				
			||||||
 | 
									flags: 0,
 | 
				
			||||||
 | 
									embeds: [],
 | 
				
			||||||
 | 
									edited_timestamp: null,
 | 
				
			||||||
 | 
									content: "Image",
 | 
				
			||||||
 | 
									components: [],
 | 
				
			||||||
 | 
									channel_id: "112760669178241024",
 | 
				
			||||||
 | 
									author: {
 | 
				
			||||||
 | 
										username: "extremity",
 | 
				
			||||||
 | 
										public_flags: 768,
 | 
				
			||||||
 | 
										id: "114147806469554185",
 | 
				
			||||||
 | 
										global_name: "Extremity",
 | 
				
			||||||
 | 
										discriminator: "0",
 | 
				
			||||||
 | 
										avatar_decoration: null,
 | 
				
			||||||
 | 
										avatar: "6628aaf6b27219c36e2d3b5cfd6d0ee6"
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									attachments: [
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											width: 1200,
 | 
				
			||||||
 | 
											url: "https://cdn.discordapp.com/attachments/112760669178241024/1128084747910918195/skull.webp",
 | 
				
			||||||
 | 
											size: 74290,
 | 
				
			||||||
 | 
											proxy_url: "https://media.discordapp.net/attachments/112760669178241024/1128084747910918195/skull.webp",
 | 
				
			||||||
 | 
											id: "1128084747910918195",
 | 
				
			||||||
 | 
											height: 628,
 | 
				
			||||||
 | 
											filename: "skull.webp",
 | 
				
			||||||
 | 
											content_type: "image/webp"
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									]
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								pinned: false,
 | 
				
			||||||
 | 
								message_reference: {
 | 
				
			||||||
 | 
									message_id: "1128084748338741392",
 | 
				
			||||||
 | 
									guild_id: "112760669178241024",
 | 
				
			||||||
 | 
									channel_id: "112760669178241024"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								mentions: [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										username: "extremity",
 | 
				
			||||||
 | 
										public_flags: 768,
 | 
				
			||||||
 | 
										member: {
 | 
				
			||||||
 | 
											roles: [
 | 
				
			||||||
 | 
												"112767366235959296",
 | 
				
			||||||
 | 
												"118924814567211009",
 | 
				
			||||||
 | 
												"199995902742626304",
 | 
				
			||||||
 | 
												"204427286542417920",
 | 
				
			||||||
 | 
												"222168467627835392",
 | 
				
			||||||
 | 
												"271173313575780353",
 | 
				
			||||||
 | 
												"392141548932038658",
 | 
				
			||||||
 | 
												"1040735082610167858",
 | 
				
			||||||
 | 
												"372954403902193689",
 | 
				
			||||||
 | 
												"1124134606514442300",
 | 
				
			||||||
 | 
												"585531096071012409"
 | 
				
			||||||
 | 
											],
 | 
				
			||||||
 | 
											premium_since: "2022-04-20T21:11:14.016000+00:00",
 | 
				
			||||||
 | 
											pending: false,
 | 
				
			||||||
 | 
											nick: "Tap to add a nickname",
 | 
				
			||||||
 | 
											mute: false,
 | 
				
			||||||
 | 
											joined_at: "2022-04-20T20:16:02.828000+00:00",
 | 
				
			||||||
 | 
											flags: 0,
 | 
				
			||||||
 | 
											deaf: false,
 | 
				
			||||||
 | 
											communication_disabled_until: null,
 | 
				
			||||||
 | 
											avatar: "a_4ea72c7b058ad848c9d9d35479fac26e"
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										id: "114147806469554185",
 | 
				
			||||||
 | 
										global_name: "Extremity",
 | 
				
			||||||
 | 
										discriminator: "0",
 | 
				
			||||||
 | 
										avatar_decoration: null,
 | 
				
			||||||
 | 
										avatar: "6628aaf6b27219c36e2d3b5cfd6d0ee6"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								],
 | 
				
			||||||
 | 
								mention_roles: [],
 | 
				
			||||||
 | 
								mention_everyone: false,
 | 
				
			||||||
 | 
								member: {
 | 
				
			||||||
 | 
									roles: [
 | 
				
			||||||
 | 
										"112767366235959296",
 | 
				
			||||||
 | 
										"118924814567211009",
 | 
				
			||||||
 | 
										"199995902742626304",
 | 
				
			||||||
 | 
										"204427286542417920",
 | 
				
			||||||
 | 
										"222168467627835392",
 | 
				
			||||||
 | 
										"271173313575780353",
 | 
				
			||||||
 | 
										"392141548932038658",
 | 
				
			||||||
 | 
										"1040735082610167858",
 | 
				
			||||||
 | 
										"372954403902193689",
 | 
				
			||||||
 | 
										"1124134606514442300",
 | 
				
			||||||
 | 
										"585531096071012409"
 | 
				
			||||||
 | 
									],
 | 
				
			||||||
 | 
									premium_since: "2022-04-20T21:11:14.016000+00:00",
 | 
				
			||||||
 | 
									pending: false,
 | 
				
			||||||
 | 
									nick: "Tap to add a nickname",
 | 
				
			||||||
 | 
									mute: false,
 | 
				
			||||||
 | 
									joined_at: "2022-04-20T20:16:02.828000+00:00",
 | 
				
			||||||
 | 
									flags: 0,
 | 
				
			||||||
 | 
									deaf: false,
 | 
				
			||||||
 | 
									communication_disabled_until: null,
 | 
				
			||||||
 | 
									avatar: "a_4ea72c7b058ad848c9d9d35479fac26e"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								id: "1128084851279536279",
 | 
				
			||||||
 | 
								flags: 0,
 | 
				
			||||||
 | 
								embeds: [],
 | 
				
			||||||
 | 
								edited_timestamp: "2023-07-10T22:08:57.442417+00:00",
 | 
				
			||||||
 | 
								content: "Edit",
 | 
				
			||||||
 | 
								components: [],
 | 
				
			||||||
 | 
								channel_id: "112760669178241024",
 | 
				
			||||||
 | 
								author: {
 | 
				
			||||||
 | 
									username: "extremity",
 | 
				
			||||||
 | 
									public_flags: 768,
 | 
				
			||||||
 | 
									id: "114147806469554185",
 | 
				
			||||||
 | 
									global_name: "Extremity",
 | 
				
			||||||
 | 
									discriminator: "0",
 | 
				
			||||||
 | 
									avatar_decoration: null,
 | 
				
			||||||
 | 
									avatar: "6628aaf6b27219c36e2d3b5cfd6d0ee6"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								attachments: [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										width: 2048,
 | 
				
			||||||
 | 
										url: "https://cdn.discordapp.com/attachments/112760669178241024/1128084851023675515/RDT_20230704_0936184915846675925224905.jpg",
 | 
				
			||||||
 | 
										size: 85906,
 | 
				
			||||||
 | 
										proxy_url: "https://media.discordapp.net/attachments/112760669178241024/1128084851023675515/RDT_20230704_0936184915846675925224905.jpg",
 | 
				
			||||||
 | 
										id: "1128084851023675515",
 | 
				
			||||||
 | 
										height: 1536,
 | 
				
			||||||
 | 
										filename: "RDT_20230704_0936184915846675925224905.jpg",
 | 
				
			||||||
 | 
										content_type: "image/jpeg"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								],
 | 
				
			||||||
 | 
								guild_id: "112760669178241024"
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		sticker: {
 | 
							sticker: {
 | 
				
			||||||
			id: "1106366167788044450",
 | 
								id: "1106366167788044450",
 | 
				
			||||||
			type: 0,
 | 
								type: 0,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								types.d.ts
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								types.d.ts
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -81,6 +81,11 @@ namespace R {
 | 
				
			||||||
		room_id: string
 | 
							room_id: string
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						export type RoomMember = {
 | 
				
			||||||
 | 
							avatar_url: string
 | 
				
			||||||
 | 
							display_name: string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	export type FileUploaded = {
 | 
						export type FileUploaded = {
 | 
				
			||||||
		content_uri: string
 | 
							content_uri: string
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue