Fix widget message persistence

This commit is contained in:
rajchales-monito
2026-07-23 22:53:07 +02:00
parent b56469e774
commit 7b6d855fec
2 changed files with 99 additions and 27 deletions
+32 -1
View File
@@ -63,6 +63,7 @@ async function route(req, res) {
if (url.pathname === "/api/widget/config" && req.method === "GET") return widgetConfig(res, url);
if (url.pathname === "/api/widget/conversations" && req.method === "POST") return createConversation(req, res);
if (url.pathname.match(/^\/api\/widget\/conversations\/[^/]+$/) && req.method === "GET") return getVisitorConversation(res, url);
if (url.pathname.match(/^\/api\/widget\/conversations\/[^/]+\/messages$/) && req.method === "POST") return createVisitorMessage(req, res, url);
if (url.pathname.match(/^\/api\/widget\/conversations\/[^/]+\/events$/) && req.method === "GET") return eventStream(req, res, url, "visitor");
if (url.pathname.match(/^\/api\/widget\/conversations\/[^/]+\/typing$/) && req.method === "POST") return visitorTyping(req, res, url);
@@ -325,6 +326,13 @@ function widgetConfig(res, url) {
return json(res, 200, { site: formatSite(site), publicBaseUrl: PUBLIC_BASE_URL });
}
function getVisitorConversation(res, url) {
const conversation = findConversation(publicIdFrom(url));
if (!conversation) return json(res, 404, { error: "conversation_not_found" });
if (conversation.visitor_token !== url.searchParams.get("visitorToken")) return json(res, 403, { error: "forbidden" });
return json(res, 200, conversationDetails(conversation));
}
async function createConversation(req, res) {
const body = await readJson(req, 8_000_000);
if (!body.message || !String(body.message).trim()) return json(res, 400, { error: "message_required" });
@@ -371,7 +379,7 @@ async function createConversation(req, res) {
const conversation = db.prepare("SELECT * FROM conversations WHERE id = ?").get(insert);
publish("admin", { type: "conversation:new", conversation: formatConversationSummary(conversation) });
publishConversation(conversation, { type: "message:new", payload: conversationDetails(conversation) });
return json(res, 201, { conversation: conversationDetails(conversation), visitorToken });
return json(res, 201, conversationDetails(conversation));
}
async function createVisitorMessage(req, res, url) {
@@ -382,6 +390,7 @@ async function createVisitorMessage(req, res, url) {
if (!conversation) return json(res, 404, { error: "conversation_not_found" });
const messageId = insertMessage(conversation.id, "visitor", conversation.visitor_name || "Visitor", String(body.message).trim());
saveAttachments(conversation.id, messageId, body.attachments || []);
updateVisitorContext(conversation.id, body);
bumpConversation(conversation.id, conversation.status === "resolved" ? "open" : conversation.status);
const updated = findConversation(conversation.public_id);
publishConversation(updated, { type: "message:new", payload: conversationDetails(updated) });
@@ -482,6 +491,28 @@ function bumpConversation(conversationId, status) {
`).run(status, conversationId);
}
function updateVisitorContext(conversationId, body) {
db.prepare(`
UPDATE conversations
SET current_url = COALESCE(?, current_url),
referrer = COALESCE(?, referrer),
browsing_history_json = COALESCE(?, browsing_history_json),
device_json = COALESCE(?, device_json),
language = COALESCE(?, language),
timezone = COALESCE(?, timezone),
updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`).run(
nullish(body.currentUrl),
nullish(body.referrer),
body.browsingHistory ? JSON.stringify(body.browsingHistory) : null,
body.device ? JSON.stringify(body.device) : null,
nullish(body.language),
nullish(body.timezone),
conversationId
);
}
function conversationDetails(conversation) {
const messages = db.prepare("SELECT * FROM messages WHERE conversation_id = ? ORDER BY id ASC").all(conversation.id);
const attachments = db.prepare("SELECT * FROM attachments WHERE conversation_id = ? ORDER BY id ASC").all(conversation.id);