From ab034ab598b2e1012798f73a836bf13b4a65ea0b Mon Sep 17 00:00:00 2001 From: Alex Southwell <4596216+saphid@users.noreply.github.com> Date: Tue, 3 Nov 2026 13:01:34 +1100 Subject: [PATCH] fix(server): html_preview no longer splits an emoji in a long console line Co-Authored-By: Claude Opus 5.5 --- apps/server/src/htmlRender/HtmlRender.test.ts | 12 ++++++++++-- apps/server/src/htmlRender/headlessChrome.ts | 7 +++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/server/src/htmlRender/HtmlRender.test.ts b/apps/server/src/htmlRender/HtmlRender.test.ts index 1916327672516..fc01613f5dfa2 100644 --- a/apps/server/src/htmlRender/HtmlRender.test.ts +++ b/apps/server/src/htmlRender/HtmlRender.test.ts @@ -350,16 +350,24 @@ fs.createReadStream(null, { fd: 3 }).on("end", quit).on("data", (chunk) => { for (const { id, method, sessionId } of messages.map((raw) => JSON.parse(raw))) { if (method === "Browser.close") quit(); reply({ id, sessionId, result: results[method] ?? {} }); - if (method === "Page.navigate") reply({ sessionId, method: "Page.loadEventFired", params: {} }); + if (method === "Page.navigate") { + const value = "x" + "\u{1F600}".repeat(300); + const params = { type: "log", args: [{ type: "string", value }] }; + reply({ sessionId, method: "Runtime.consoleAPICalled", params }); + reply({ sessionId, method: "Page.loadEventFired", params: {} }); + } } }); `, { mode: 0o755 }, ); - yield* HtmlRender.HtmlRender.use((htmlRender) => + const preview = yield* HtmlRender.HtmlRender.use((htmlRender) => htmlRender.preview({ html: "

x

" }), ).pipe(Effect.provide(layerHtmlRender(executable))); + const logged = preview.consoleMessages[0]?.text ?? ""; + expect(logged.isWellFormed()).toBe(true); + expect(logged).toHaveLength(500); const exitedBy = yield* fileSystem.readFileString(exitRecord).pipe(Effect.option); expect(Option.getOrElse(exitedBy, () => "killed by a signal")).toBe("asked to close"); diff --git a/apps/server/src/htmlRender/headlessChrome.ts b/apps/server/src/htmlRender/headlessChrome.ts index 13ce0c6845740..5e2a5bb0d5891 100644 --- a/apps/server/src/htmlRender/headlessChrome.ts +++ b/apps/server/src/htmlRender/headlessChrome.ts @@ -316,10 +316,13 @@ const launchBrowser = Effect.fnUntraced(function* (input: { return yield* Effect.void; } const text = consoleMessage.text.replaceAll(PAGE_URL, PAGE_NAME); + // Half an emoji serializes to a lone surrogate escape, which provider JSON parsers reject. + const last = text.charCodeAt(MAX_CONSOLE_TEXT_CHARS - 1); + const end = + last >= 0xd800 && last <= 0xdbff ? MAX_CONSOLE_TEXT_CHARS - 1 : MAX_CONSOLE_TEXT_CHARS; page.consoleMessages.push({ level: consoleMessage.level, - text: - text.length > MAX_CONSOLE_TEXT_CHARS ? `${text.slice(0, MAX_CONSOLE_TEXT_CHARS)}…` : text, + text: text.length > MAX_CONSOLE_TEXT_CHARS ? `${text.slice(0, end)}…` : text, }); return yield* Effect.void; });