diff --git a/src/m2d/converters/event-to-message.js b/src/m2d/converters/event-to-message.js
index ebbe9e1..b52717d 100644
--- a/src/m2d/converters/event-to-message.js
+++ b/src/m2d/converters/event-to-message.js
@@ -330,9 +330,9 @@ async function uploadEndOfMessageSpriteSheet(content, attachments, pendingFiles,
*/
async function handleRoomOrMessageLinks(input, di) {
let offset = 0
- for (const match of [...input.matchAll(/("?https:\/\/matrix.to\/#\/(![^"/, ?)]+)(?:\/(\$[^"/ ?)]+))?(?:\?[^",:!? )]*?)?)(">|[,<\n )]|$)/g)]) {
+ for (const match of [...input.matchAll(/("?https:\/\/matrix.to\/#\/((?:#|%23|!)[^"/, ?)]+)(?:\/(\$[^"/ ?)]+))?(?:\?[^",:!? )]*?)?)(">|[,<\n )]|$)/g)]) {
assert(typeof match.index === "number")
- const [_, attributeValue, roomID, eventID, endMarker] = match
+ let [_, attributeValue, roomID, eventID, endMarker] = match
let result
const resultType = endMarker === '">' ? "html" : "plain"
@@ -350,6 +350,16 @@ async function handleRoomOrMessageLinks(input, di) {
// Don't process links that are part of the reply fallback, they'll be removed entirely by turndown
if (input.slice(match.index + match[0].length + offset).startsWith("In reply to")) continue
+ // Resolve room alias to room ID if needed
+ roomID = decodeURIComponent(roomID)
+ if (roomID[0] === "#") {
+ try {
+ roomID = await di.api.getAlias(roomID)
+ } catch (e) {
+ continue // Room alias is unresolvable, so it can't be converted
+ }
+ }
+
const channelID = select("channel_room", "channel_id", {room_id: roomID}).pluck().get()
if (!channelID) continue
if (!eventID) {
diff --git a/src/m2d/converters/event-to-message.test.js b/src/m2d/converters/event-to-message.test.js
index a97fd26..145e9ec 100644
--- a/src/m2d/converters/event-to-message.test.js
+++ b/src/m2d/converters/event-to-message.test.js
@@ -2957,6 +2957,133 @@ test("event2message: mentioning bridged rooms works (plaintext body)", async t =
)
})
+test("event2message: mentioning bridged rooms by alias works", async t => {
+ let called = 0
+ t.deepEqual(
+ await eventToMessage({
+ content: {
+ msgtype: "m.text",
+ body: "wrong body",
+ format: "org.matrix.custom.html",
+ formatted_body: `I'm just worm-farm testing channel mentions`
+ },
+ event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
+ origin_server_ts: 1688301929913,
+ room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe",
+ sender: "@cadence:cadence.moe",
+ type: "m.room.message",
+ unsigned: {
+ age: 405299
+ }
+ }, {}, {
+ api: {
+ async getAlias(alias) {
+ called++
+ t.equal(alias, "#worm-farm:cadence.moe")
+ return "!BnKuBPCvyfOkhcUjEu:cadence.moe"
+ }
+ }
+ }),
+ {
+ ensureJoined: [],
+ messagesToDelete: [],
+ messagesToEdit: [],
+ messagesToSend: [{
+ username: "cadence [they]",
+ content: "I'm just <#1100319550446252084> testing channel mentions",
+ avatar_url: undefined,
+ allowed_mentions: {
+ parse: ["users", "roles"]
+ }
+ }]
+ }
+ )
+ t.equal(called, 1)
+})
+
+test("event2message: mentioning bridged rooms by alias works (plaintext body)", async t => {
+ let called = 0
+ t.deepEqual(
+ await eventToMessage({
+ content: {
+ msgtype: "m.text",
+ body: `I'm just https://matrix.to/#/#worm-farm:cadence.moe?via=cadence.moe testing channel mentions`
+ },
+ event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
+ origin_server_ts: 1688301929913,
+ room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe",
+ sender: "@cadence:cadence.moe",
+ type: "m.room.message",
+ unsigned: {
+ age: 405299
+ }
+ }, {}, {
+ api: {
+ async getAlias(alias) {
+ called++
+ t.equal(alias, "#worm-farm:cadence.moe")
+ return "!BnKuBPCvyfOkhcUjEu:cadence.moe"
+ }
+ }
+ }),
+ {
+ ensureJoined: [],
+ messagesToDelete: [],
+ messagesToEdit: [],
+ messagesToSend: [{
+ username: "cadence [they]",
+ content: "I'm just <#1100319550446252084> testing channel mentions",
+ avatar_url: undefined,
+ allowed_mentions: {
+ parse: ["users", "roles"]
+ }
+ }]
+ }
+ )
+ t.equal(called, 1)
+})
+
+test("event2message: mentioning bridged rooms by alias skips the link when alias is unresolvable", async t => {
+ let called = 0
+ t.deepEqual(
+ await eventToMessage({
+ content: {
+ msgtype: "m.text",
+ body: `I'm just https://matrix.to/#/#worm-farm:cadence.moe?via=cadence.moe and https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe?via=cadence.moe testing channel mentions`
+ },
+ event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
+ origin_server_ts: 1688301929913,
+ room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe",
+ sender: "@cadence:cadence.moe",
+ type: "m.room.message",
+ unsigned: {
+ age: 405299
+ }
+ }, {}, {
+ api: {
+ async getAlias(alias) {
+ called++
+ throw new MatrixServerError("Alias doesn't exist or something")
+ }
+ }
+ }),
+ {
+ ensureJoined: [],
+ messagesToDelete: [],
+ messagesToEdit: [],
+ messagesToSend: [{
+ username: "cadence [they]",
+ content: "I'm just and <#1100319550446252084> testing channel mentions",
+ avatar_url: undefined,
+ allowed_mentions: {
+ parse: ["users", "roles"]
+ }
+ }]
+ }
+ )
+ t.equal(called, 1)
+})
+
test("event2message: mentioning known bridged events works (plaintext body)", async t => {
t.deepEqual(
await eventToMessage({
diff --git a/src/matrix/api.js b/src/matrix/api.js
index f9d3e08..c2b2384 100644
--- a/src/matrix/api.js
+++ b/src/matrix/api.js
@@ -367,6 +367,16 @@ async function ackEvent(event, mxid) {
await sendReadReceipt(event.room_id, event.event_id, mxid)
}
+/**
+ * Resolve a room alias to a room ID.
+ * @param {string} alias
+ */
+async function getAlias(alias) {
+ /** @type {Ty.R.ResolvedRoom} */
+ const root = await mreq.mreq("GET", `/client/v3/directory/room/${encodeURIComponent(alias)}`)
+ return root.room_id
+}
+
module.exports.path = path
module.exports.register = register
module.exports.createRoom = createRoom
@@ -395,3 +405,4 @@ module.exports.ping = ping
module.exports.getMedia = getMedia
module.exports.sendReadReceipt = sendReadReceipt
module.exports.ackEvent = ackEvent
+module.exports.getAlias = getAlias
diff --git a/src/types.d.ts b/src/types.d.ts
index b99046b..3298c40 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -336,6 +336,11 @@ export namespace R {
room_id: string
room_type?: string
}
+
+ export type ResolvedRoom = {
+ room_id: string
+ servers: string[]
+ }
}
export type Pagination = {