| author | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-02-11 16:58:34 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-02-11 16:58:34 UTC |
| parent | a616528a5a90f29d893c83e60ed0b799edf116ad |
| borogove/ChatMessage.hx | +32 | -0 |
| borogove/ChatMessageBuilder.hx | +6 | -0 |
| borogove/Message.hx | +15 | -0 |
| borogove/persistence/IDB.js | +1 | -0 |
| npm/index.ts | +1 | -0 |
diff --git a/borogove/ChatMessage.hx b/borogove/ChatMessage.hx index 8de1dee..16cefc4 100644 --- a/borogove/ChatMessage.hx +++ b/borogove/ChatMessage.hx @@ -23,6 +23,31 @@ import borogove.Message; import borogove.Stanza; import borogove.Util; +@:expose +@:nullSafety(StrictThreaded) +#if cpp +@:build(HaxeCBridge.expose()) +@:build(HaxeSwiftBridge.expose()) +#end +class LinkMetadata { + public final about: String; + public final url: String; + public final title: Null<String>; + public final description: Null<String>; + public final image: ReadOnlyArray<String>; + public final video: ReadOnlyArray<String>; + + @:allow(borogove) + private function new(about: String, url: Null<String>, title: Null<String>, description: Null<String>, image: ReadOnlyArray<String>, video: ReadOnlyArray<String>) { + this.about = about; + this.url = url ?? about; + this.title = title; + this.description = description; + this.image = image; + this.video = video; + } +} + @:expose @:nullSafety(StrictThreaded) #if cpp @@ -212,6 +237,11 @@ class ChatMessage { **/ public final encryption: Null<EncryptionInfo>; + /** + Metadata about links associated with this message + **/ + public final linkMetadata: ReadOnlyArray<LinkMetadata>; + @:allow(borogove) private final stanza: Null<Stanza>; @@ -241,6 +271,7 @@ class ChatMessage { ?versions: Array<ChatMessage>, ?payloads: Array<Stanza>, ?encryption: Null<EncryptionInfo>, + ?linkMetadata: Array<LinkMetadata>, ?stanza: Null<Stanza>, }) { this.localId = params.localId; @@ -267,6 +298,7 @@ class ChatMessage { this.versions = params.versions ?? []; this.payloads = params.payloads ?? []; this.encryption = params.encryption; + this.linkMetadata = params.linkMetadata ?? []; this.stanza = params.stanza; } diff --git a/borogove/ChatMessageBuilder.hx b/borogove/ChatMessageBuilder.hx index 79bc7af..71d63c7 100644 --- a/borogove/ChatMessageBuilder.hx +++ b/borogove/ChatMessageBuilder.hx @@ -137,6 +137,11 @@ class ChatMessageBuilder { **/ public var encryption: Null<EncryptionInfo>; + /** + Metadata about links associated with this message + **/ + public var linkMetadata: Array<LinkMetadata> = []; + /** WARNING: if you set this, you promise all the attributes of this builder match it **/ @@ -355,6 +360,7 @@ class ChatMessageBuilder { versions: versions, payloads: payloads, encryption: encryption, + linkMetadata: linkMetadata, stanza: stanza, }); } diff --git a/borogove/Message.hx b/borogove/Message.hx index 4f396e7..11a274b 100644 --- a/borogove/Message.hx +++ b/borogove/Message.hx @@ -1,5 +1,6 @@ package borogove; +import borogove.ChatMessage; import borogove.Reaction; using Lambda; using StringTools; @@ -335,6 +336,20 @@ class Message { msg.localId = replaceId; } + for (desc in stanza.allTags("Description", "http://www.w3.org/1999/02/22-rdf-syntax-ns#")) { + final about = desc.attr.get("{http://www.w3.org/1999/02/22-rdf-syntax-ns#}about"); + if (about != null) { + msg.linkMetadata.push(new LinkMetadata( + about, + desc.getChildText("url", "https://ogp.me/ns#"), + desc.getChildText("title", "https://ogp.me/ns#"), + desc.getChildText("description", "https://ogp.me/ns#"), + desc.allTags("image", "https://ogp.me/ns#").map(el -> el.getText()), + desc.allTags("video", "https://ogp.me/ns#").map(el -> el.getText()) + )); + } + } + return new Message(msg.chatId(), msg.senderId, msg.threadId, ChatMessageStanza(msg.build()), encryptionInfo); } } diff --git a/borogove/persistence/IDB.js b/borogove/persistence/IDB.js index 86a7a62..e25ab58 100644 --- a/borogove/persistence/IDB.js +++ b/borogove/persistence/IDB.js @@ -164,6 +164,7 @@ export default async (dbname, media, tokenize, stemmer) => { message.replyTo = value.replyTo.map((r) => borogove_JID.parse(r)); message.threadId = value.threadId; message.attachments = value.attachments; + message.linkMetadata = value.linkMetadata ?? []; message.reactions = hydrateReactions(value.reactions, message.timestamp); message.text = value.text; message.lang = value.lang; diff --git a/npm/index.ts b/npm/index.ts index f1aa81a..4ac5b20 100644 --- a/npm/index.ts +++ b/npm/index.ts @@ -28,6 +28,7 @@ export { borogove_FormOption as FormOption, borogove_Hash as Hash, borogove_Identicon as Identicon, + borogove_LinkMetadata as LinkMetadata, borogove_Notification as Notification, borogove_Participant as Participant, borogove_Persistence as Persistence,