git » sdk » commit 0954252

Fix reply stub hydration

author Stephen Paul Weber
2026-05-01 00:44:30 UTC
committer Stephen Paul Weber
2026-05-01 00:44:30 UTC
parent 6ccd2385782a0c5937d5d5d2a347340f68b4bac6

Fix reply stub hydration

borogove/persistence/IDB.js +3 -5
borogove/persistence/Sqlite.hx +1 -1
test/idb.spec.ts +56 -0
test/sqlite.spec.ts +9 -25

diff --git a/borogove/persistence/IDB.js b/borogove/persistence/IDB.js
index 10b874c..1117836 100644
--- a/borogove/persistence/IDB.js
+++ b/borogove/persistence/IDB.js
@@ -586,7 +586,7 @@ export default async (dbname, media, tokenize, stemmer) => {
 			return await hydrateMessage(message);
 		},
 
-		storeMessages(account, messages) {
+		async storeMessages(account, messages) {
 			return Promise.all(messages.map(m =>
 				new Promise(resolve => this.storeMessage(account, m, resolve))
 			));
@@ -605,7 +605,7 @@ export default async (dbname, media, tokenize, stemmer) => {
 					this.getMessage(account, message.chatId(), message.replyToMessage.serverId, message.replyToMessage.localId) :
 					Promise.resolve(message.replyToMessage)
 			).then((replyToMessage) => {
-				message.replyToMessage = replyToMessage;
+				message.replyToMessage = replyToMessage ?? message.replyToMessage;
 				const tx = db.transaction(["messages", "reactions"], "readwrite");
 				const store = tx.objectStore("messages");
 				return Promise.all([
@@ -647,9 +647,7 @@ export default async (dbname, media, tokenize, stemmer) => {
 								event.target.result.continue();
 							} else {
 								message.reactions = reactions;
-								const req = store.put(serializeMessage(account, message));
-								req.onerror = () => { window.mylog.push("MSG STORE ERROR: " + req.error.name + " " + req.error.message); }
-								callback(message);
+								promisifyRequest(store.put(serializeMessage(account, message))).then(() => callback(message));
 							}
 						};
 						cursor.onerror = console.error;
diff --git a/borogove/persistence/Sqlite.hx b/borogove/persistence/Sqlite.hx
index f8831dd..e6168de 100644
--- a/borogove/persistence/Sqlite.hx
+++ b/borogove/persistence/Sqlite.hx
@@ -394,7 +394,7 @@ class Sqlite implements Persistence implements KeyValueStore {
 				chatIds.push(message.chatId());
 				localIds.push(message.localId);
 			}
-			if (message.replyToMessage != null && message.replyToMessage.serverIdBy == null) {
+			if (message.replyToMessage != null) {
 				replyTos.push({ chatId: message.chatId(), serverId: message.replyToMessage.serverId, localId: message.replyToMessage.localId });
 			}
 		}
diff --git a/test/idb.spec.ts b/test/idb.spec.ts
index 7a5ebf6..a77c6fd 100644
--- a/test/idb.spec.ts
+++ b/test/idb.spec.ts
@@ -866,6 +866,62 @@ test("hydrate message with incomplete replyToMessage", async ({ page }) => {
 	expect(result.replyServerId).toBe("parent");
 });
 
+test("hydrate message with incomplete replyToMessage", async ({ page }) => {
+	page.route("https://localhost/", (route) =>
+		route.fulfill({ body: "<html></html>" }),
+	);
+	const code = fs.readFileSync("playwright/.cache/borogove.js", "utf8");
+	await page.goto("https://localhost/");
+	const result = await page.evaluate(async (code) => {
+		const blob = new Blob([code], { type: "text/javascript" });
+		const borogove = await import(URL.createObjectURL(blob));
+
+		const mediaStore = await borogove.persistence.MediaStoreCache("snikket");
+		const persistence = await borogove.persistence.IDB("snikket", mediaStore);
+
+		const builder = new borogove.ChatMessageBuilder({
+			serverId: "parent",
+			serverIdBy: "hatter@example.com",
+			localId: "loc1",
+			senderId: "hatter@example.com",
+			direction: 0,
+		});
+		builder.sortId = "a0";
+		builder.to = borogove.JID.parse("alice@example.com");
+		builder.from = borogove.JID.parse("hatter@example.com");
+		builder.recipients = [builder.to];
+		builder.replyTo = [builder.from];
+		const parentStub = builder.build();
+
+		builder.setBody(borogove.Html.text("Hello"));
+		const parentMsg = builder.build();
+
+		const builder2 = new borogove.ChatMessageBuilder({
+			serverId: "child",
+			serverIdBy: "hatter@example.com",
+			localId: "loc2",
+			senderId: "hatter@example.com",
+			direction: 0,
+		});
+		builder2.sortId = "a1";
+		builder2.to = borogove.JID.parse("alice@example.com");
+		builder2.from = borogove.JID.parse("hatter@example.com");
+		builder2.recipients = [builder2.to];
+		builder2.replyTo = [builder2.from];
+		builder2.replyToMessage = parentStub;
+		const childMsg = builder2.build();
+
+		await persistence.storeMessages("alice@example.com", [parentMsg]);
+		const [childStored] = await persistence.storeMessages("alice@example.com", [
+			childMsg,
+		]);
+
+		return childStored.replyToMessage.body().toPlainText();
+	}, code);
+
+	expect(result).toBe("Hello");
+});
+
 test("storeChats and getChats with status", async ({ page }) => {
 	page.route("https://localhost/", route => route.fulfill({ body: "<html></html>" }));
 	const code = fs.readFileSync("playwright/.cache/borogove.js", "utf8");
diff --git a/test/sqlite.spec.ts b/test/sqlite.spec.ts
index f19d4fc..e4cf67d 100644
--- a/test/sqlite.spec.ts
+++ b/test/sqlite.spec.ts
@@ -1463,43 +1463,27 @@ test.describe("not webkit", () => {
 					localId: "loc2",
 					senderId: "hatter@example.com",
 					direction: 0,
-					type: borogove.MessageType.MessageChannel,
 				});
 				builder2.sortId = "a1";
 				builder2.to = borogove.JID.parse("alice@example.com");
 				builder2.from = borogove.JID.parse("hatter@example.com");
 				builder2.recipients = [builder2.to];
 				builder2.replyTo = [builder2.from];
-				builder2.replyToMessage = parentMsg;
+				builder2.replyToMessage = parentStub;
 				const childMsg = builder2.build();
 
-				try {
-					await persistence.storeMessages("alice@example.com", [
-						parentMsg,
-						childMsg,
-					]);
-					const retrievedChild = await persistence.getMessage(
-						"alice@example.com",
-						"hatter@example.com",
-						"child",
-						"loc2",
-					);
-					return {
-						hasReply: !!retrievedChild.replyToMessage,
-						replyServerId: retrievedChild.replyToMessage
-							? retrievedChild.replyToMessage.serverId
-							: null,
-					};
-				} catch (e) {
-					console.error(e, e.result);
-					throw e.result ? JSON.stringify(e.result) : e.message;
-				}
+				await persistence.storeMessages("alice@example.com", [parentMsg]);
+				const [childStored] = await persistence.storeMessages(
+					"alice@example.com",
+					[childMsg],
+				);
+
+				return childStored.replyToMessage.body().toPlainText();
 			},
 			[code, sqlite, worker1],
 		);
 
-		expect(result.hasReply).toBe(true);
-		expect(result.replyServerId).toBe("parent");
+		expect(result).toBe("Hello");
 	});
 
 	test("storeChats and getChats with status", async ({ page }) => {