diff --git a/d2m/actions/create-room.js b/d2m/actions/create-room.js index 2095130..b641d37 100644 --- a/d2m/actions/create-room.js +++ b/d2m/actions/create-room.js @@ -17,7 +17,6 @@ const ks = sync.require("../../matrix/kstate") const inflightRoomCreate = new Map() /** - * Async because it gets all room state from the homeserver. * @param {string} roomID */ async function roomToKState(roomID) { @@ -37,17 +36,12 @@ function applyKStateDiffToRoom(roomID, kstate) { } /** - * @param {{id: string, name: string, topic?: string?, type: number}} channel + * @param {{id: string, name: string, topic?: string?}} channel * @param {{id: string}} guild * @param {string?} customName */ function convertNameAndTopic(channel, guild, customName) { - let channelPrefix = - ( channel.type === DiscordTypes.ChannelType.PublicThread ? "[⛓️] " - : channel.type === DiscordTypes.ChannelType.PrivateThread ? "[🔒⛓️] " - : channel.type === DiscordTypes.ChannelType.GuildVoice ? "[🔊] " - : "") - const chosenName = customName || (channelPrefix + channel.name); + const convertedName = customName || channel.name; const maybeTopicWithPipe = channel.topic ? ` | ${channel.topic}` : ''; const maybeTopicWithNewlines = channel.topic ? `${channel.topic}\n\n` : ''; const channelIDPart = `Channel ID: ${channel.id}`; @@ -57,11 +51,10 @@ function convertNameAndTopic(channel, guild, customName) { ? `#${channel.name}${maybeTopicWithPipe}\n\n${channelIDPart}\n${guildIDPart}` : `${maybeTopicWithNewlines}${channelIDPart}\n${guildIDPart}`; - return [chosenName, convertedTopic]; + return [convertedName, convertedTopic]; } /** - * Async because it may upload the guild icon to mxc. * @param {DiscordTypes.APIGuildTextChannel | DiscordTypes.APIThreadChannel} channel * @param {DiscordTypes.APIGuild} guild */ @@ -125,21 +118,13 @@ async function createRoom(channel, guild, spaceID, kstate) { if (channel.type === DiscordTypes.ChannelType.PublicThread) threadParent = channel.parent_id const invite = threadParent ? [] : ["@cadence:cadence.moe"] // TODO - // Name and topic can be done earlier in room creation rather than in initial_state - // https://spec.matrix.org/latest/client-server-api/#creation - const name = kstate["m.room.name/"].name - delete kstate["m.room.name/"] - assert(name) - const topic = kstate["m.room.topic/"].topic - delete kstate["m.room.topic/"] - assert(topic) - const roomID = await postApplyPowerLevels(kstate, async kstate => { + const [convertedName, convertedTopic] = convertNameAndTopic(channel, guild, null) const roomID = await api.createRoom({ - name, - topic, - preset: "private_chat", // This is closest to what we want, but properties from kstate override it anyway - visibility: "private", // Not shown in the room directory + name: convertedName, + topic: convertedTopic, + preset: "private_chat", + visibility: "private", invite, initial_state: ks.kstateToState(kstate) }) @@ -202,10 +187,10 @@ function channelToGuild(channel) { 3. Get kstate for channel 4. Create room, return new ID - Ensure + sync flow: + New combined flow with ensure / sync: 1. Get IDs 2. Does room exist? - 2.5: If room does exist AND wasn't asked to sync: return here + 2.5: If room does exist AND don't need to sync: return here 3. Get kstate for channel 4. Create room with kstate if room doesn't exist 5. Get and update room state with kstate if room does exist @@ -248,7 +233,7 @@ async function _syncRoom(channelID, shouldActuallySync) { console.log(`[room sync] to matrix: ${channel.name}`) - const {spaceID, channelKState} = await channelToKState(channel, guild) // calling this in both branches because we don't want to calculate this if not syncing + const {spaceID, channelKState} = await channelToKState(channel, guild) // sync channel state to room const roomKState = await roomToKState(roomID) @@ -263,16 +248,6 @@ async function _syncRoom(channelID, shouldActuallySync) { return roomID } -/** Ensures the room exists. If it doesn't, creates the room with an accurate initial state. */ -function ensureRoom(channelID) { - return _syncRoom(channelID, false) -} - -/** Actually syncs. Gets all room state from the homeserver in order to diff, and uploads the icon to mxc if it has changed. */ -function syncRoom(channelID) { - return _syncRoom(channelID, true) -} - async function _unbridgeRoom(channelID) { /** @ts-ignore @type {DiscordTypes.APIGuildChannel} */ const channel = discord.channels.get(channelID) @@ -301,7 +276,6 @@ async function _unbridgeRoom(channelID) { /** - * Async because it gets all space state from the homeserver, then if necessary sends one state event back. * @param {DiscordTypes.APIGuildTextChannel} channel * @param {string} spaceID * @param {string} roomID @@ -324,6 +298,14 @@ async function _syncSpaceMember(channel, spaceID, roomID) { return applyKStateDiffToRoom(spaceID, spaceDiff) } +function ensureRoom(channelID) { + return _syncRoom(channelID, false) +} + +function syncRoom(channelID) { + return _syncRoom(channelID, true) +} + async function createAllForGuild(guildID) { const channelIDs = discord.guildChannelMap.get(guildID) assert.ok(channelIDs) diff --git a/d2m/actions/create-room.test.js b/d2m/actions/create-room.test.js index e40bf6f..ec5c3d3 100644 --- a/d2m/actions/create-room.test.js +++ b/d2m/actions/create-room.test.js @@ -14,49 +14,28 @@ test("channel2room: general", async t => { test("convertNameAndTopic: custom name and topic", t => { t.deepEqual( - _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 0}, {id: "456"}, "hauntings"), + _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:"}, {id: "456"}, "hauntings"), ["hauntings", "#the-twilight-zone | Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"] ) }) test("convertNameAndTopic: custom name, no topic", t => { t.deepEqual( - _convertNameAndTopic({id: "123", name: "the-twilight-zone", type: 0}, {id: "456"}, "hauntings"), + _convertNameAndTopic({id: "123", name: "the-twilight-zone"}, {id: "456"}, "hauntings"), ["hauntings", "#the-twilight-zone\n\nChannel ID: 123\nGuild ID: 456"] ) }) test("convertNameAndTopic: original name and topic", t => { t.deepEqual( - _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 0}, {id: "456"}, null), + _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:"}, {id: "456"}, null), ["the-twilight-zone", "Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"] ) }) test("convertNameAndTopic: original name, no topic", t => { t.deepEqual( - _convertNameAndTopic({id: "123", name: "the-twilight-zone", type: 0}, {id: "456"}, null), + _convertNameAndTopic({id: "123", name: "the-twilight-zone"}, {id: "456"}, null), ["the-twilight-zone", "Channel ID: 123\nGuild ID: 456"] ) }) - -test("convertNameAndTopic: public thread icon", t => { - t.deepEqual( - _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 11}, {id: "456"}, null), - ["[⛓️] the-twilight-zone", "Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"] - ) -}) - -test("convertNameAndTopic: private thread icon", t => { - t.deepEqual( - _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 12}, {id: "456"}, null), - ["[🔒⛓️] the-twilight-zone", "Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"] - ) -}) - -test("convertNameAndTopic: voice channel icon", t => { - t.deepEqual( - _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 2}, {id: "456"}, null), - ["[🔊] the-twilight-zone", "Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"] - ) -}) diff --git a/d2m/actions/create-space.js b/d2m/actions/create-space.js index 838bef9..46fa71f 100644 --- a/d2m/actions/create-space.js +++ b/d2m/actions/create-space.js @@ -1,6 +1,6 @@ // @ts-check -const assert = require("assert").strict +const assert = require("assert") const DiscordTypes = require("discord-api-types/v10") const passthrough = require("../../passthrough") @@ -84,31 +84,11 @@ async function syncSpace(guildID) { console.log(`[space sync] to matrix: ${guild.name}`) - // sync guild state to space + // sync channel state to room const spaceKState = await createRoom.roomToKState(spaceID) const spaceDiff = ks.diffKState(spaceKState, guildKState) await createRoom.applyKStateDiffToRoom(spaceID, spaceDiff) - // guild icon was changed, so room avatars need to be updated as well as the space ones - // doing it this way rather than calling syncRoom for great efficiency gains - const newAvatarState = spaceDiff["m.room.avatar/"] - if (guild.icon && newAvatarState?.url) { - // don't try to update rooms with custom avatars though - const roomsWithCustomAvatars = db.prepare("SELECT room_id FROM channel_room WHERE custom_avatar IS NOT NULL").pluck().all() - - const childRooms = ks.kstateToState(spaceKState).filter(({type, state_key, content}) => { - return type === "m.space.child" && "via" in content && roomsWithCustomAvatars.includes(state_key) - }).map(({state_key}) => state_key) - - for (const roomID of childRooms) { - const avatarEventContent = await api.getStateEvent(roomID, "m.room.avatar", "") - if (avatarEventContent.url !== newAvatarState.url) { - await api.sendState(roomID, "m.room.avatar", "", newAvatarState) - } - } - } - - return spaceID } diff --git a/d2m/actions/register-user.test.js b/d2m/actions/register-user.test.js index 74818ea..34470ba 100644 --- a/d2m/actions/register-user.test.js +++ b/d2m/actions/register-user.test.js @@ -3,27 +3,7 @@ const {_memberToStateContent} = require("./register-user") const {test} = require("supertape") const testData = require("../../test/data") -test("member2state: without member nick or avatar", async t => { - t.deepEqual( - await _memberToStateContent(testData.member.kumaccino.user, testData.member.kumaccino, testData.guild.general.id), - { - avatar_url: "mxc://cadence.moe/UpAeIqeclhKfeiZNdIWNcXXL", - displayname: "kumaccino", - membership: "join", - "moe.cadence.ooye.member": { - avatar: "/avatars/113340068197859328/b48302623a12bc7c59a71328f72ccb39.png?size=1024" - }, - "uk.half-shot.discord.member": { - bot: false, - displayColor: 10206929, - id: "113340068197859328", - username: "@kumaccino" - } - } - ) -}) - -test("member2state: with member nick and avatar", async t => { +test("member2state: general", async t => { t.deepEqual( await _memberToStateContent(testData.member.sheep.user, testData.member.sheep, testData.guild.general.id), { diff --git a/d2m/converters/user-to-mxid.js b/d2m/converters/user-to-mxid.js index 1fe8ffc..89e47a4 100644 --- a/d2m/converters/user-to-mxid.js +++ b/d2m/converters/user-to-mxid.js @@ -39,7 +39,6 @@ function* generateLocalpartAlternatives(preferences) { let i = 2 while (true) { yield best + (i++) - /* c8 ignore next */ } } @@ -70,7 +69,7 @@ function userToSimName(user) { for (const suggestion of generateLocalpartAlternatives(preferences)) { if (!matches.includes(suggestion)) return suggestion } - /* c8 ignore next */ + throw new Error(`Ran out of suggestions when generating sim name. downcased: "${downcased}"`) } diff --git a/d2m/discord-command-handler.js b/d2m/discord-command-handler.js deleted file mode 100644 index 1bd52c8..0000000 --- a/d2m/discord-command-handler.js +++ /dev/null @@ -1,142 +0,0 @@ -// @ts-check - -const assert = require("assert").strict -const util = require("util") -const DiscordTypes = require("discord-api-types/v10") -const {discord, sync, db} = require("../passthrough") -/** @type {import("../matrix/api")}) */ -const api = sync.require("../matrix/api") -/** @type {import("../matrix/file")} */ -const file = sync.require("../matrix/file") - -const PREFIX = "//" - -let buttons = [] - -/** - * @param {string} channelID where to add the button - * @param {string} messageID where to add the button - * @param {string} emoji emoji to add as a button - * @param {string} userID only listen for responses from this user - * @returns {Promise} - */ -async function addButton(channelID, messageID, emoji, userID) { - await discord.snow.channel.createReaction(channelID, messageID, emoji) - return new Promise(resolve => { - buttons.push({channelID, messageID, userID, resolve, created: Date.now()}) - }) -} - -// Clear out old buttons every so often to free memory -setInterval(() => { - const now = Date.now() - buttons = buttons.filter(b => now - b.created < 2*60*60*1000) -}, 10*60*1000) - -/** @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data */ -function onReactionAdd(data) { - const button = buttons.find(b => b.channelID === data.channel_id && b.messageID === data.message_id && b.userID === data.user_id) - if (button) { - buttons = buttons.filter(b => b !== button) // remove button data so it can't be clicked again - button.resolve(data) - } -} - -/** - * @callback CommandExecute - * @param {DiscordTypes.GatewayMessageCreateDispatchData} message - * @param {DiscordTypes.APIGuildTextChannel} channel - * @param {DiscordTypes.APIGuild} guild - * @param {Partial} [ctx] - */ - -/** - * @typedef Command - * @property {string[]} aliases - * @property {(message: DiscordTypes.GatewayMessageCreateDispatchData, channel: DiscordTypes.APIGuildTextChannel, guild: DiscordTypes.APIGuild) => Promise} execute - */ - -/** @param {CommandExecute} execute */ -function replyctx(execute) { - /** @type {CommandExecute} */ - return function(message, channel, guild, ctx = {}) { - ctx.message_reference = { - message_id: message.id, - channel_id: channel.id, - guild_id: guild.id, - fail_if_not_exists: false - } - return execute(message, channel, guild, ctx) - } -} - -/** @type {Command[]} */ -const commands = [{ - aliases: ["icon", "avatar", "roomicon", "roomavatar", "channelicon", "channelavatar"], - execute: replyctx( - async (message, channel, guild, ctx) => { - // Guard - const roomID = db.prepare("SELECT room_id FROM channel_room WHERE channel_id = ?").pluck().get(channel.id) - if (!roomID) return discord.snow.channel.createMessage(channel.id, { - ...ctx, - content: "This channel isn't bridged to the other side." - }) - - // Current avatar - const avatarEvent = await api.getStateEvent(roomID, "m.room.avatar", "") - const avatarURLParts = avatarEvent?.url.match(/^mxc:\/\/([^/]+)\/(\w+)$/) - let currentAvatarMessage = - ( avatarURLParts ? `Current room-specific avatar: https://matrix.cadence.moe/_matrix/media/r0/download/${avatarURLParts[1]}/${avatarURLParts[2]}` - : "No avatar. Now's your time to strike. Use `//icon` again with a link or upload to set the room-specific avatar.") - - // Next potential avatar - const nextAvatarURL = message.attachments.find(a => a.content_type?.startsWith("image/"))?.url || message.content.match(/https?:\/\/[^ ]+\.[^ ]+\.(?:png|jpg|jpeg|webp)\b/)?.[0] - let nextAvatarMessage = - ( nextAvatarURL ? `\nYou want to set it to: ${nextAvatarURL}\nHit ✅ to make it happen.` - : "") - - const sent = await discord.snow.channel.createMessage(channel.id, { - ...ctx, - content: currentAvatarMessage + nextAvatarMessage - }) - - if (nextAvatarURL) { - addButton(channel.id, sent.id, "✅", message.author.id).then(async data => { - const mxcUrl = await file.uploadDiscordFileToMxc(nextAvatarURL) - await api.sendState(roomID, "m.room.avatar", "", { - url: mxcUrl - }) - db.prepare("UPDATE channel_room SET custom_avatar = ? WHERE channel_id = ?").run(mxcUrl, channel.id) - await discord.snow.channel.createMessage(channel.id, { - ...ctx, - content: "Your creation is unleashed. Any complaints will be redirected to Grelbo." - }) - }) - } - } - ) -}, { - aliases: ["invite"], - execute: replyctx( - async (message, channel, guild, ctx) => { - return discord.snow.channel.createMessage(channel.id, { - ...ctx, - content: "This command isn't implemented yet." - }) - } - ) -}] - -/** @type {CommandExecute} */ -async function execute(message, channel, guild) { - if (!message.content.startsWith(PREFIX)) return - const words = message.content.slice(PREFIX.length).split(" ") - const commandName = words[0] - const command = commands.find(c => c.aliases.includes(commandName)) - if (!command) return - - await command.execute(message, channel, guild) -} - -module.exports.execute = execute -module.exports.onReactionAdd = onReactionAdd diff --git a/d2m/event-dispatcher.js b/d2m/event-dispatcher.js index 6939c59..9bb07c0 100644 --- a/d2m/event-dispatcher.js +++ b/d2m/event-dispatcher.js @@ -18,8 +18,6 @@ const createRoom = sync.require("./actions/create-room") const createSpace = sync.require("./actions/create-space") /** @type {import("../matrix/api")}) */ const api = sync.require("../matrix/api") -/** @type {import("./discord-command-handler")}) */ -const discordCommandHandler = sync.require("./discord-command-handler") let lastReportedEvent = 0 @@ -158,9 +156,7 @@ module.exports = { if (!channel.guild_id) return // Nothing we can do in direct messages. const guild = client.guilds.get(channel.guild_id) if (!isGuildAllowed(guild.id)) return - - await sendMessage.sendMessage(message, guild), - await discordCommandHandler.execute(message, channel, guild) + await sendMessage.sendMessage(message, guild) }, /** @@ -195,7 +191,6 @@ module.exports = { */ async onReactionAdd(client, data) { if (data.user_id === client.user.id) return // m2d reactions are added by the discord bot user - do not reflect them back to matrix. - discordCommandHandler.onReactionAdd(data) if (data.emoji.id !== null) return // TODO: image emoji reactions await addReaction.addReaction(data) }, diff --git a/db/data-for-test.sql b/db/data-for-test.sql index e88b967..ec9f9ec 100644 --- a/db/data-for-test.sql +++ b/db/data-for-test.sql @@ -93,7 +93,6 @@ INSERT INTO file (discord_url, mxc_url) VALUES ('https://cdn.discordapp.com/attachments/112760669178241024/1141501302497615912/piper_2.png', 'mxc://cadence.moe/KQYdXKRcHWjDYDLPkTOOWOjA'), ('https://cdn.discordapp.com/attachments/112760669178241024/1128084851023675515/RDT_20230704_0936184915846675925224905.jpg', 'mxc://cadence.moe/WlAbFSiNRIHPDEwKdyPeGywa'), ('https://cdn.discordapp.com/guilds/112760669178241024/users/134826546694193153/avatars/38dd359aa12bcd52dd3164126c587f8c.png?size=1024', 'mxc://cadence.moe/rfemHmAtcprjLEiPiEuzPhpl'), -('https://cdn.discordapp.com/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024', 'mxc://cadence.moe/zKXGZhmImMHuGQZWJEFKJbsF'), -('https://cdn.discordapp.com/avatars/113340068197859328/b48302623a12bc7c59a71328f72ccb39.png?size=1024', 'mxc://cadence.moe/UpAeIqeclhKfeiZNdIWNcXXL'); +('https://cdn.discordapp.com/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024', 'mxc://cadence.moe/zKXGZhmImMHuGQZWJEFKJbsF'); COMMIT; diff --git a/m2d/converters/event-to-message.js b/m2d/converters/event-to-message.js index dde77b7..b2c56a9 100644 --- a/m2d/converters/event-to-message.js +++ b/m2d/converters/event-to-message.js @@ -32,7 +32,7 @@ function eventToMessage(event) { }) } else if (event.content.msgtype === "m.emote") { messages.push({ - content: `\* _${displayName} ${event.content.body}_`, + content: `*${displayName} ${event.content.body}*`, username: displayName, avatar_url: avatarURL }) diff --git a/matrix/api.js b/matrix/api.js index 7253a1a..2e0763e 100644 --- a/matrix/api.js +++ b/matrix/api.js @@ -190,7 +190,6 @@ module.exports.inviteToRoom = inviteToRoom module.exports.leaveRoom = leaveRoom module.exports.getEvent = getEvent module.exports.getAllState = getAllState -module.exports.getStateEvent = getStateEvent module.exports.getJoinedMembers = getJoinedMembers module.exports.sendState = sendState module.exports.sendEvent = sendEvent diff --git a/matrix/file.js b/matrix/file.js index 7d74d5d..965ec1c 100644 --- a/matrix/file.js +++ b/matrix/file.js @@ -27,15 +27,15 @@ async function uploadDiscordFileToMxc(path) { } // Are we uploading this file RIGHT NOW? Return the same inflight promise with the same resolution - const existingInflight = inflight.get(url) - if (existingInflight) { - return existingInflight + let existing = inflight.get(url) + if (typeof existing === "string") { + return existing } // Has this file already been uploaded in the past? Grab the existing copy from the database. - const existingFromDb = db.prepare("SELECT mxc_url FROM file WHERE discord_url = ?").pluck().get(url) - if (typeof existingFromDb === "string") { - return existingFromDb + existing = db.prepare("SELECT mxc_url FROM file WHERE discord_url = ?").pluck().get(url) + if (typeof existing === "string") { + return existing } // Download from Discord diff --git a/matrix/txnid.test.js b/matrix/txnid.test.js deleted file mode 100644 index 4db873c..0000000 --- a/matrix/txnid.test.js +++ /dev/null @@ -1,12 +0,0 @@ -// @ts-check - -const {test} = require("supertape") -const txnid = require("./txnid") - -test("txnid: generates different values each run", t => { - const one = txnid.makeTxnId() - t.ok(one) - const two = txnid.makeTxnId() - t.ok(two) - t.notEqual(two, one) -}) diff --git a/stdin.js b/stdin.js index a687c6c..ce612f5 100644 --- a/stdin.js +++ b/stdin.js @@ -12,7 +12,6 @@ const createRoom = sync.require("./d2m/actions/create-room") const registerUser = sync.require("./d2m/actions/register-user") const mreq = sync.require("./matrix/mreq") const api = sync.require("./matrix/api") -const file = sync.require("./matrix/file") const sendEvent = sync.require("./m2d/actions/send-event") const eventDispatcher = sync.require("./d2m/event-dispatcher") const ks = sync.require("./matrix/kstate") diff --git a/test/data.js b/test/data.js index a4d836d..6ed2f42 100644 --- a/test/data.js +++ b/test/data.js @@ -98,46 +98,6 @@ module.exports = { } }, member: { - kumaccino: { - avatar: null, - communication_disabled_until: null, - flags: 0, - joined_at: "2015-11-11T09:55:40.321000+00:00", - nick: null, - pending: false, - premium_since: null, - roles: [ - "112767366235959296", "118924814567211009", - "199995902742626304", "204427286542417920", - "222168467627835392", "238028326281805825", - "259806643414499328", "265239342648131584", - "271173313575780353", "287733611912757249", - "225744901915148298", "305775031223320577", - "318243902521868288", "348651574924541953", - "349185088157777920", "378402925128712193", - "392141548932038658", "393912152173576203", - "482860581670486028", "495384759074160642", - "638988388740890635", "373336013109461013", - "530220455085473813", "454567553738473472", - "790724320824655873", "1040735082610167858", - "695946570482450442", "849737964090556488" - ], - user: { - id: "113340068197859328", - username: "kumaccino", - avatar: "b48302623a12bc7c59a71328f72ccb39", - discriminator: "0", - public_flags: 128, - flags: 128, - banner: null, - accent_color: 10206929, - global_name: "kumaccino", - avatar_decoration_data: null, - banner_color: "#9bbed1" - }, - mute: false, - deaf: false - }, sheep: { avatar: "38dd359aa12bcd52dd3164126c587f8c", communication_disabled_until: null, diff --git a/test/test.js b/test/test.js index e19f8ff..606bd4b 100644 --- a/test/test.js +++ b/test/test.js @@ -20,7 +20,6 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not require("../matrix/kstate.test") require("../matrix/api.test") require("../matrix/read-registration.test") -require("../matrix/txnid.test") require("../d2m/converters/message-to-event.test") require("../d2m/converters/message-to-event.embeds.test") require("../d2m/converters/edit-to-changes.test")