Compare commits

...

3 commits

11 changed files with 384 additions and 31 deletions

View file

@ -283,6 +283,7 @@ async function _unbridgeRoom(channelID) {
assert.ok(spaceID)
// remove room from being a space member
await api.sendState(roomID, "m.space.parent", spaceID, {})
await api.sendState(spaceID, "m.space.child", roomID, {})
// send a notification in the room

View file

@ -24,7 +24,7 @@ async function editMessage(message, guild) {
await api.sendEvent(roomID, eventType, newContentWithoutType, senderMxid)
// Ensure the database is up to date.
// The columns are event_id, event_type, event_subtype, message_id, channel_id, part, source. Only event_subtype could potentially be changed by a replacement event.
const subtype = newContentWithoutType.msgtype ?? null
const subtype = newContentWithoutType.msgtype || null
db.prepare("UPDATE event_message SET event_subtype = ? WHERE event_id = ?").run(subtype, oldID)
}

View file

@ -23,7 +23,7 @@ async function editToChanges(message, guild, api) {
const roomID = db.prepare("SELECT room_id FROM channel_room WHERE channel_id = ?").pluck().get(message.channel_id)
/** @type {string?} */
let senderMxid = db.prepare("SELECT mxid FROM sim WHERE discord_id = ?").pluck().get(message.author.id) ?? null
let senderMxid = db.prepare("SELECT mxid FROM sim WHERE discord_id = ?").pluck().get(message.author.id) || null
if (senderMxid) {
const senderIsInRoom = db.prepare("SELECT * FROM sim_member WHERE room_id = ? and mxid = ?").get(roomID, senderMxid)
if (!senderIsInRoom) {
@ -66,7 +66,7 @@ async function editToChanges(message, guild, api) {
// Find a new event to pair it with...
for (let i = 0; i < oldEventRows.length; i++) {
const olde = oldEventRows[i]
if (olde.event_type === newe.$type && olde.event_subtype === (newe.msgtype ?? null)) { // The spec does allow subtypes to change, so I can change this condition later if I want to
if (olde.event_type === newe.$type && olde.event_subtype === (newe.msgtype || null)) { // The spec does allow subtypes to change, so I can change this condition later if I want to
// Found one!
// Set up the pairing
eventsToReplace.push({

View file

@ -103,6 +103,32 @@ test("edit2changes: add caption back to that image", async t => {
t.deepEqual(eventsToReplace, [])
})
test("edit2changes: stickers and attachments are not changed, only the content can be edited", async t => {
const {eventsToRedact, eventsToReplace, eventsToSend} = await editToChanges(data.message_update.edited_content_with_sticker_and_attachments, data.guild.general, {})
t.deepEqual(eventsToRedact, [])
t.deepEqual(eventsToSend, [])
t.deepEqual(eventsToReplace, [{
oldID: "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qdFv4",
newContent: {
$type: "m.room.message",
msgtype: "m.text",
body: "* only the content can be edited",
"m.mentions": {},
// *** Replaced With: ***
"m.new_content": {
msgtype: "m.text",
body: "only the content can be edited",
"m.mentions": {}
},
"m.relates_to": {
rel_type: "m.replace",
event_id: "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qdFv4"
}
}
}])
})
test("edit2changes: edit of reply to skull webp attachment with content", async t => {
const {eventsToRedact, eventsToReplace, eventsToSend} = await editToChanges(data.message_update.edit_of_reply_to_skull_webp_attachment_with_content, data.guild.general, {})
t.deepEqual(eventsToRedact, [])

View file

@ -83,7 +83,10 @@ INSERT INTO event_message (event_id, event_type, event_subtype, message_id, chan
('$vgTKOR5ZTYNMKaS7XvgEIDaOWZtVCEyzLLi5Pc5Gz4M', 'm.room.message', 'm.text', '1128084851279536279', '112760669178241024', 0, 1),
('$YUJFa5j0ZJe7PUvD2DykRt9g51RoadUEYmuJLdSEbJ0', 'm.room.message', 'm.image', '1128084851279536279', '112760669178241024', 1, 1),
('$oLyUTyZ_7e_SUzGNWZKz880ll9amLZvXGbArJCKai2Q', 'm.room.message', 'm.text', '1128084748338741392', '112760669178241024', 0, 1),
('$FchUVylsOfmmbj-VwEs5Z9kY49_dt2zd0vWfylzy5Yo', 'm.room.message', 'm.text', '1143121514925928541', '1100319550446252084', 0, 1);
('$FchUVylsOfmmbj-VwEs5Z9kY49_dt2zd0vWfylzy5Yo', 'm.room.message', 'm.text', '1143121514925928541', '1100319550446252084', 0, 1),
('$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qdFv4', 'm.room.message', 'm.text', '1106366167788044450', '122155380120748034', 0, 1),
('$Ijf1MFCD39ktrNHxrA-i2aKoRWNYdAV2ZXYQeiZIgEU', 'm.room.message', 'm.image', '1106366167788044450', '122155380120748034', 0, 0),
('$f9cjKiacXI9qPF_nUAckzbiKnJEi0LM399kOkhdd8f8', 'm.sticker', NULL, '1106366167788044450', '122155380120748034', 0, 0);
INSERT INTO file (discord_url, mxc_url) VALUES
('https://cdn.discordapp.com/attachments/497161332244742154/1124628646431297546/image.png', 'mxc://cadence.moe/qXoZktDqNtEGuOCZEADAMvhM'),

View file

@ -2,19 +2,41 @@
const Ty = require("../../types")
const DiscordTypes = require("discord-api-types/v10")
const markdown = require("discord-markdown")
const chunk = require("chunk-text")
const TurndownService = require("turndown")
const passthrough = require("../../passthrough")
const { sync, db, discord } = passthrough
/** @type {import("../../matrix/file")} */
const file = sync.require("../../matrix/file")
// https://github.com/mixmark-io/turndown/blob/97e4535ca76bb2e70d9caa2aa4d4686956b06d44/src/utilities.js#L26C28-L33C2
const BLOCK_ELEMENTS = [
"ADDRESS", "ARTICLE", "ASIDE", "AUDIO", "BLOCKQUOTE", "BODY", "CANVAS",
"CENTER", "DD", "DETAILS", "DIR", "DIV", "DL", "DT", "FIELDSET", "FIGCAPTION", "FIGURE",
"FOOTER", "FORM", "FRAMESET", "H1", "H2", "H3", "H4", "H5", "H6", "HEADER",
"HGROUP", "HR", "HTML", "ISINDEX", "LI", "MAIN", "MENU", "NAV", "NOFRAMES",
"NOSCRIPT", "OL", "OUTPUT", "P", "PRE", "SECTION", "SUMMARY", "TABLE", "TBODY", "TD",
"TFOOT", "TH", "THEAD", "TR", "UL"
]
const turndownService = new TurndownService({
hr: "----"
})
turndownService.addRule("strikethrough", {
filter: ["del", "s", "strike"],
replacement: function (content) {
return "~~" + content + "~~"
}
})
/**
* @param {Ty.Event.Outer<Ty.Event.M_Room_Message>} event
*/
function eventToMessage(event) {
/** @type {(DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer}[]})[]} */
const messages = []
let messages = []
let displayName = event.sender
let avatarURL = undefined
@ -24,20 +46,51 @@ function eventToMessage(event) {
// TODO: get the media repo domain and the avatar url from the matrix member event
}
if (event.content.msgtype === "m.text") {
messages.push({
content: event.content.body,
username: displayName,
avatar_url: avatarURL
})
} else if (event.content.msgtype === "m.emote") {
messages.push({
content: `\* _${displayName} ${event.content.body}_`,
username: displayName,
avatar_url: avatarURL
// Convert content depending on what the message is
let content = event.content.body // ultimate fallback
if (event.content.format === "org.matrix.custom.html" && event.content.formatted_body) {
let input = event.content.formatted_body
if (event.content.msgtype === "m.emote") {
input = `* ${displayName} ${input}`
}
// Note: Element's renderers on Web and Android currently collapse whitespace, like the browser does. Turndown also collapses whitespace which is good for me.
// If later I'm using a client that doesn't collapse whitespace and I want turndown to follow suit, uncomment the following line of code, and it Just Works:
// input = input.replace(/ /g, "&nbsp;")
// There is also a corresponding test to uncomment, named "event2message: whitespace is retained"
// The matrix spec hasn't decided whether \n counts as a newline or not, but I'm going to count it, because if it's in the data it's there for a reason.
// But I should not count it if it's between block elements.
input = input.replace(/(<\/?([^ >]+)[^>]*>)?\n(<\/?([^ >]+)[^>]*>)?/g, (whole, beforeContext, beforeTag, afterContext, afterTag) => {
if (typeof beforeTag !== "string" && typeof afterTag !== "string") {
return "<br>"
}
beforeContext = beforeContext || ""
beforeTag = beforeTag || ""
afterContext = afterContext || ""
afterTag = afterTag || ""
if (!BLOCK_ELEMENTS.includes(beforeTag.toUpperCase()) && !BLOCK_ELEMENTS.includes(afterTag.toUpperCase())) {
return beforeContext + "<br>" + afterContext
} else {
return whole
}
})
// @ts-ignore
content = turndownService.turndown(input)
// It's optimised for commonmark, we need to replace the space-space-newline with just newline
content = content.replace(/ \n/g, "\n")
}
// Split into 2000 character chunks
const chunks = chunk(content, 2000)
messages = messages.concat(chunks.map(content => ({
content,
username: displayName,
avatar_url: avatarURL
})))
return messages
}

View file

@ -4,6 +4,12 @@ const {test} = require("supertape")
const {eventToMessage} = require("./event-to-message")
const data = require("../../test/data")
function sameFirstContentAndWhitespace(t, a, b) {
const a2 = JSON.stringify(a[0].content)
const b2 = JSON.stringify(b[0].content)
t.equal(a2, b2)
}
test("event2message: janky test", t => {
t.deepEqual(
eventToMessage({
@ -28,6 +34,165 @@ test("event2message: janky test", t => {
)
})
test("event2message: basic html is converted to markdown", t => {
t.deepEqual(
eventToMessage({
content: {
msgtype: "m.text",
body: "wrong body",
format: "org.matrix.custom.html",
formatted_body: "this <strong>is</strong> a <strong><em>test</em></strong> of <del>formatting</del>"
},
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
origin_server_ts: 1688301929913,
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe",
sender: "@cadence:cadence.moe",
type: "m.room.message",
unsigned: {
age: 405299
}
}),
[{
username: "cadence",
content: "this **is** a **_test_** of ~~formatting~~",
avatar_url: undefined
}]
)
})
test("event2message: markdown syntax is escaped", t => {
t.deepEqual(
eventToMessage({
content: {
msgtype: "m.text",
body: "wrong body",
format: "org.matrix.custom.html",
formatted_body: "this **is** an <strong><em>extreme</em></strong> \\*test\\* of"
},
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
origin_server_ts: 1688301929913,
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe",
sender: "@cadence:cadence.moe",
type: "m.room.message",
unsigned: {
age: 405299
}
}),
[{
username: "cadence",
content: "this \\*\\*is\\*\\* an **_extreme_** \\\\\\*test\\\\\\* of",
avatar_url: undefined
}]
)
})
test("event2message: html lines are bridged correctly", t => {
t.deepEqual(
eventToMessage({
content: {
msgtype: "m.text",
body: "wrong body",
format: "org.matrix.custom.html",
formatted_body: "<p>paragraph one<br>line <em>two</em><br>line three<br><br>paragraph two\nline <em>two</em>\nline three\n\nparagraph three</p><p>paragraph four\nline two<br>line three\nline four</p>paragraph five"
},
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
origin_server_ts: 1688301929913,
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe",
sender: "@cadence:cadence.moe",
type: "m.room.message",
unsigned: {
age: 405299
}
}),
[{
username: "cadence",
content: "paragraph one\nline _two_\nline three\n\nparagraph two\nline _two_\nline three\n\nparagraph three\n\nparagraph four\nline two\nline three\nline four\n\nparagraph five",
avatar_url: undefined
}]
)
})
/*test("event2message: whitespace is retained", t => {
t.deepEqual(
eventToMessage({
content: {
msgtype: "m.text",
body: "wrong body",
format: "org.matrix.custom.html",
formatted_body: "line one: test test<br>line two: <strong>test</strong> <strong>test</strong><br>line three: <strong>test test</strong><br>line four: test<strong> </strong>test<br> line five"
},
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
origin_server_ts: 1688301929913,
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe",
sender: "@cadence:cadence.moe",
type: "m.room.message",
unsigned: {
age: 405299
}
}),
[{
username: "cadence",
content: "line one: test test\nline two: **test** **test**\nline three: **test test**\nline four: test test\n line five",
avatar_url: undefined
}]
)
})*/
test("event2message: whitespace is collapsed", t => {
sameFirstContentAndWhitespace(
t,
eventToMessage({
content: {
msgtype: "m.text",
body: "wrong body",
format: "org.matrix.custom.html",
formatted_body: "line one: test test<br>line two: <strong>test</strong> <strong>test</strong><br>line three: <strong>test test</strong><br>line four: test<strong> </strong>test<br> line five"
},
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
origin_server_ts: 1688301929913,
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe",
sender: "@cadence:cadence.moe",
type: "m.room.message",
unsigned: {
age: 405299
}
}),
[{
username: "cadence",
content: "line one: test test\nline two: **test** **test**\nline three: **test test**\nline four: test test\nline five",
avatar_url: undefined
}]
)
})
test("event2message: lists are bridged correctly", t => {
sameFirstContentAndWhitespace(
t,
eventToMessage({
"type": "m.room.message",
"sender": "@cadence:cadence.moe",
"content": {
"msgtype": "m.text",
"body": "* line one\n* line two\n* line three\n * nested one\n * nested two\n* line four",
"format": "org.matrix.custom.html",
"formatted_body": "<ul>\n<li>line one</li>\n<li>line two</li>\n<li>line three\n<ul>\n<li>nested one</li>\n<li>nested two</li>\n</ul>\n</li>\n<li>line four</li>\n</ul>\n"
},
"origin_server_ts": 1692967314062,
"unsigned": {
"age": 112,
"transaction_id": "m1692967313951.441"
},
"event_id": "$l-xQPY5vNJo3SNxU9d8aOWNVD1glMslMyrp4M_JEF70",
"room_id": "!BpMdOUkWWhFxmTrENV:cadence.moe"
}),
[{
username: "cadence",
content: "* line one\n* line two\n* line three\n * nested one\n * nested two\n* line four",
avatar_url: undefined
}]
)
})
test("event2message: long messages are split", t => {
t.deepEqual(
eventToMessage({
@ -55,3 +220,29 @@ test("event2message: long messages are split", t => {
}]
)
})
test("event2message: m.emote markdown syntax is escaped", t => {
t.deepEqual(
eventToMessage({
content: {
msgtype: "m.emote",
body: "wrong body",
format: "org.matrix.custom.html",
formatted_body: "shows you **her** <strong><em>extreme</em></strong> \\*test\\* of"
},
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
origin_server_ts: 1688301929913,
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe",
sender: "@cadence:cadence.moe",
type: "m.room.message",
unsigned: {
age: 405299
}
}),
[{
username: "cadence",
content: "\\* cadence shows you \\*\\*her\\*\\* **_extreme_** \\\\\\*test\\\\\\* of",
avatar_url: undefined
}]
)
})

54
package-lock.json generated
View file

@ -10,6 +10,7 @@
"license": "MIT",
"dependencies": {
"better-sqlite3": "^8.3.0",
"chunk-text": "^2.0.1",
"cloudstorm": "^0.8.0",
"discord-markdown": "git+https://git.sr.ht/~cadence/nodejs-discord-markdown#440130ef343c8183a81c7c09809731484aa3a182",
"heatsync": "^2.4.1",
@ -20,7 +21,8 @@
"node-fetch": "^2.6.7",
"prettier-bytes": "^1.0.4",
"snowtransfer": "^0.8.0",
"try-to-catch": "^3.0.1"
"try-to-catch": "^3.0.1",
"turndown": "^7.1.2"
},
"devDependencies": {
"@types/node": "^18.16.0",
@ -29,7 +31,7 @@
"cross-env": "^7.0.3",
"discord-api-types": "^0.37.53",
"supertape": "^8.3.0",
"tap-dot": "github:cloudrac3r/tap-dot#223a4e67a6f7daf015506a12a7af74605f06c7f4"
"tap-dot": "github:cloudrac3r/tap-dot#9dd7750ececeae3a96afba91905be812b6b2cc2d"
}
},
"node_modules/@babel/runtime": {
@ -732,6 +734,18 @@
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
},
"node_modules/chunk-text": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/chunk-text/-/chunk-text-2.0.1.tgz",
"integrity": "sha512-ER6TSpe2DT4wjOVOKJ3FFAYv7wE77HA/Ztz88Peiv3lq/2oVMsItYJJsVVI0xNZM8cdImOOTNqlw+LQz7gYdJg==",
"dependencies": {
"runes": "^0.4.3"
},
"bin": {
"chunk": "bin/server.js",
"chunk-text": "bin/server.js"
}
},
"node_modules/ci-info": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
@ -1057,6 +1071,11 @@
"simple-markdown": "^0.7.2"
}
},
"node_modules/domino": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz",
"integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ=="
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -2518,15 +2537,16 @@
"dev": true
},
"node_modules/readable-stream": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz",
"integrity": "sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==",
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.2.tgz",
"integrity": "sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==",
"dev": true,
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10"
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -2645,6 +2665,14 @@
"node": "*"
}
},
"node_modules/runes": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/runes/-/runes-0.4.3.tgz",
"integrity": "sha512-K6p9y4ZyL9wPzA+PMDloNQPfoDGTiFYDvdlXznyGKgD10BJpcAosvATKrExRKOrNLgD8E7Um7WGW0lxsnOuNLg==",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -3043,8 +3071,8 @@
},
"node_modules/tap-dot": {
"version": "2.0.0",
"resolved": "git+ssh://git@github.com/cloudrac3r/tap-dot.git#223a4e67a6f7daf015506a12a7af74605f06c7f4",
"integrity": "sha512-nhpVoX/s4IJJdm7OymbZ1rdZNlqt3l/yQ9Z9if06jcgRNto6QAZOrLIvdCILYQ6GE0mu+cyVA8s24amdwbvHiQ==",
"resolved": "git+ssh://git@github.com/cloudrac3r/tap-dot.git#9dd7750ececeae3a96afba91905be812b6b2cc2d",
"integrity": "sha512-SLg6KF3cSkKII+5hA/we9FjnMCrL5uk0wYap7RXD9KJziy7xqZolvEOamt3CJlm5LSzRXIGblm3nmhY/EBE3AA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3058,7 +3086,7 @@
"node_modules/tap-out": {
"version": "3.2.1",
"resolved": "git+ssh://git@github.com/cloudrac3r/tap-out.git#1b4ec6084aedb9f44ccaa0c7185ff9bfd83da771",
"integrity": "sha512-hyMMeN6jagEyeEOq7Xyg3GNIAR3iUDDocaoK5QRPjnEGbFZOYJ39Dkn7BsFUXyGVl+s4b3zPkDcTS38+6KTXCQ==",
"integrity": "sha512-55eUSaX5AeEOqJMRlj9XSqUlLV/yYPOPeC3kOFqjmorq6/jlH5kIeqpgLNW5PlPEAuggzYREYYXqrN8E37ZPfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3215,6 +3243,14 @@
"node": "*"
}
},
"node_modules/turndown": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.1.2.tgz",
"integrity": "sha512-ntI9R7fcUKjqBP6QU8rBK2Ehyt8LAzt3UBT9JR9tgo6GtuKvyUzpayWmeMKJw1DPdXzktvtIT8m2mVXz+bL/Qg==",
"dependencies": {
"domino": "^2.1.6"
}
},
"node_modules/type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",

View file

@ -16,6 +16,7 @@
"license": "MIT",
"dependencies": {
"better-sqlite3": "^8.3.0",
"chunk-text": "^2.0.1",
"cloudstorm": "^0.8.0",
"discord-markdown": "git+https://git.sr.ht/~cadence/nodejs-discord-markdown#440130ef343c8183a81c7c09809731484aa3a182",
"heatsync": "^2.4.1",
@ -26,7 +27,8 @@
"node-fetch": "^2.6.7",
"prettier-bytes": "^1.0.4",
"snowtransfer": "^0.8.0",
"try-to-catch": "^3.0.1"
"try-to-catch": "^3.0.1",
"turndown": "^7.1.2"
},
"devDependencies": {
"@types/node": "^18.16.0",
@ -35,7 +37,7 @@
"cross-env": "^7.0.3",
"discord-api-types": "^0.37.53",
"supertape": "^8.3.0",
"tap-dot": "github:cloudrac3r/tap-dot#223a4e67a6f7daf015506a12a7af74605f06c7f4"
"tap-dot": "github:cloudrac3r/tap-dot#9dd7750ececeae3a96afba91905be812b6b2cc2d"
},
"scripts": {
"test": "cross-env FORCE_COLOR=true supertape --no-check-assertions-count --format tap test/test.js | tap-dot",

View file

@ -1250,6 +1250,47 @@ module.exports = {
tts: false,
type: 0
},
edited_content_with_sticker_and_attachments: {
id: "1106366167788044450",
type: 0,
content: "only the content can be edited",
channel_id: "122155380120748034",
author: {
id: "113340068197859328",
username: "Cookie 🍪",
global_name: null,
display_name: null,
avatar: "b48302623a12bc7c59a71328f72ccb39",
discriminator: "7766",
public_flags: 128,
avatar_decoration: null
},
attachments: [{
id: "1106366167486038016",
filename: "image.png",
size: 127373,
url: "https://cdn.discordapp.com/attachments/122155380120748034/1106366167486038016/image.png",
proxy_url: "https://media.discordapp.net/attachments/122155380120748034/1106366167486038016/image.png",
width: 333,
height: 287,
content_type: "image/png"
}],
embeds: [],
mentions: [],
mention_roles: [],
pinned: false,
mention_everyone: false,
tts: false,
timestamp: "2023-05-11T23:44:09.690000+00:00",
edited_timestamp: "2023-05-11T23:44:19.690000+00:00",
flags: 0,
components: [],
sticker_items: [{
id: "1106323941183717586",
format_type: 1,
name: "pomu puff"
}]
},
edit_of_reply_to_skull_webp_attachment_with_content: {
type: 19,
tts: false,

6
types.d.ts vendored
View file

@ -67,10 +67,10 @@ export namespace Event {
}
export type M_Room_Message = {
msgtype: "m.text"
msgtype: "m.text" | "m.emote"
body: string
formatted_body?: "org.matrix.custom.html"
format?: string
format?: "org.matrix.custom.html"
formatted_body?: string
}
export type M_Room_Member = {