git » sdk » commit bfd9ebb

Parse link metadata

author Stephen Paul Weber
2026-02-11 16:58:34 UTC
committer Stephen Paul Weber
2026-02-11 16:58:34 UTC
parent a616528a5a90f29d893c83e60ed0b799edf116ad

Parse link metadata

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,