From f9b4552907c6b7ee1ebcb2c387f624789bd64b8c Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 5 Mar 2026 18:28:04 -0800 Subject: [PATCH 1/6] [web_core] MarkdownRenderer is now async. --- renderers/web_core/CHANGELOG.md | 9 +++++++++ renderers/web_core/package.json | 2 +- renderers/web_core/src/v0_8/types/types.ts | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 renderers/web_core/CHANGELOG.md diff --git a/renderers/web_core/CHANGELOG.md b/renderers/web_core/CHANGELOG.md new file mode 100644 index 000000000..b2638e27e --- /dev/null +++ b/renderers/web_core/CHANGELOG.md @@ -0,0 +1,9 @@ +## 0.8.3 + +* The `MarkdownRenderer` type is now async and returns a `Promise`. + +## 0.8.2 + +## 0.8.1 + +## 0.8.0 diff --git a/renderers/web_core/package.json b/renderers/web_core/package.json index 00236b9e8..e52fb2f48 100644 --- a/renderers/web_core/package.json +++ b/renderers/web_core/package.json @@ -1,6 +1,6 @@ { "name": "@a2ui/web_core", - "version": "0.8.2", + "version": "0.8.3", "description": "A2UI Core Library", "main": "./dist/src/v0_8/index.js", "types": "./dist/src/v0_8/index.d.ts", diff --git a/renderers/web_core/src/v0_8/types/types.ts b/renderers/web_core/src/v0_8/types/types.ts index 24e225db0..2cfa15298 100644 --- a/renderers/web_core/src/v0_8/types/types.ts +++ b/renderers/web_core/src/v0_8/types/types.ts @@ -514,12 +514,12 @@ export declare interface Surface { // Markdown rendering /** * Renders `markdown` using `options`. - * @returns The rendered HTML as a string. + * @returns A promise that resolves to the rendered HTML as a string. */ export declare type MarkdownRenderer = ( markdown: string, options?: MarkdownRendererOptions, -) => string; +) => Promise; /** * A map of tag names to a list of classnames to be applied to a tag. From ed254fb5b8fe74406830c73f5ba41eda8b707011 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 5 Mar 2026 18:29:29 -0800 Subject: [PATCH 2/6] [markdown-it] Made render async to conform to the MarkdownRenderer interface --- renderers/markdown/markdown-it/CHANGELOG.md | 7 +++++++ renderers/markdown/markdown-it/package.json | 2 +- .../markdown/markdown-it/src/markdown.test.ts | 20 +++++++++---------- .../markdown/markdown-it/src/markdown.ts | 6 +++--- 4 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 renderers/markdown/markdown-it/CHANGELOG.md diff --git a/renderers/markdown/markdown-it/CHANGELOG.md b/renderers/markdown/markdown-it/CHANGELOG.md new file mode 100644 index 000000000..28cfacc03 --- /dev/null +++ b/renderers/markdown/markdown-it/CHANGELOG.md @@ -0,0 +1,7 @@ +## 0.0.2 + +* Made the markdown renderer async to support async markdown renderers. + +## 0.0.1 + +* Initial release \ No newline at end of file diff --git a/renderers/markdown/markdown-it/package.json b/renderers/markdown/markdown-it/package.json index 69de3d150..03580ba74 100644 --- a/renderers/markdown/markdown-it/package.json +++ b/renderers/markdown/markdown-it/package.json @@ -1,6 +1,6 @@ { "name": "@a2ui/markdown-it", - "version": "0.0.1", + "version": "0.0.2", "description": "A Markdown renderer using markdown-it and dompurify.", "keywords": [], "homepage": "https://github.com/google/A2UI/tree/main/web#readme", diff --git a/renderers/markdown/markdown-it/src/markdown.test.ts b/renderers/markdown/markdown-it/src/markdown.test.ts index 4378f8f95..e3ca65674 100644 --- a/renderers/markdown/markdown-it/src/markdown.test.ts +++ b/renderers/markdown/markdown-it/src/markdown.test.ts @@ -50,42 +50,42 @@ describe('MarkdownItRenderer', () => { }); describe('renderMarkdown', () => { - it('renders markdown successfully', () => { - const html = renderMarkdown('# Hello World'); + it('renders markdown successfully', async () => { + const html = await renderMarkdown('# Hello World'); assert.match(html, /

Hello World<\/h1>/); }); - it('sanitizes malicious markdown links', () => { + it('sanitizes malicious markdown links', async () => { // Markdown-it strips javascript links by default, emitting the raw markdown string. // DOMPurify acts as a secondary layer of defense. const input = 'This is a test [link](javascript:alert("XSS"))'; - const html = renderMarkdown(input); + const html = await renderMarkdown(input); // Ensure the javascript protocol link is neutralized completely assert.doesNotMatch(html, /href="javascript:alert/); assert.match(html, /\[link\]\(javascript:alert\("XSS"\)\)/); // It remains raw text }); - it('safely escapes HTML input without enabling raw HTML', () => { + it('safely escapes HTML input without enabling raw HTML', async () => { const input = 'This is a test '; - const html = renderMarkdown(input); + const html = await renderMarkdown(input); // Markdown-it will escape it to <script> assert.match(html, /<script>alert\("XSS"\)<\/script>/); assert.doesNotMatch(html, /