Skip to content

Commit af31923

Browse files
papertray3claude
andcommitted
Add rendered HTML content support via Accept header
This commit adds support for retrieving rendered HTML content from markdown files using the Accept header: application/vnd.olrapi.note+html Changes: - Added ContentTypes.olrapiNoteHtml constant - Implemented renderMarkdownToHtml() method using Obsidian's MarkdownRenderer API - Updated _vaultGet() to handle HTML content type requests - Updated OpenAPI documentation with new content format - Added proper component lifecycle management to prevent memory leaks The feature integrates with Obsidian's native rendering pipeline, ensuring: - Wiki-links are converted to HTML anchors - Plugin integrations (Metadata Menu, etc.) are preserved - Callouts, embeds, and other Obsidian-specific markdown is properly rendered - Syntax highlighting for code blocks This is backward compatible and uses standard HTTP content negotiation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 615b3bc commit af31923

File tree

4 files changed

+53
-2
lines changed

4 files changed

+53
-2
lines changed

docs/src/lib/get.jsonnet

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
'$ref': '#/components/schemas/NoteJson',
1616
},
1717
},
18+
'application/vnd.olrapi.note+html': {
19+
schema: {
20+
type: 'string',
21+
description: 'Rendered HTML content from the markdown file',
22+
example: '<h1>This is my document</h1>\n<p>something else here</p>\n',
23+
},
24+
},
1825
},
1926
},
2027
'404': {

docs/src/openapi.jsonnet

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ std.manifestYamlDoc(
131131
get: Get {
132132
tags: ['Active File'],
133133
summary: 'Return the content of the active file open in Obsidian.\n',
134-
description: 'Returns the content of the currently active file in Obsidian.\n\nIf you specify the header `Accept: application/vnd.olrapi.note+json`, will return a JSON representation of your note including parsed tag and frontmatter data as well as filesystem metadata. See "responses" below for details.\n',
134+
description: 'Returns the content of the currently active file in Obsidian.\n\nContent format options via Accept header:\n- `Accept: application/vnd.olrapi.note+json` - Returns a JSON representation including parsed tag and frontmatter data as well as filesystem metadata\n- `Accept: application/vnd.olrapi.note+html` - Returns rendered HTML from markdown files\n- Default - Returns raw file content\n\nSee "responses" below for details.\n',
135135
},
136136
put: Put {
137137
tags: [
@@ -166,7 +166,7 @@ std.manifestYamlDoc(
166166
'Vault Files',
167167
],
168168
summary: 'Return the content of a single file in your vault.\n',
169-
description: 'Returns the content of the file at the specified path in your vault should the file exist.\n\nIf you specify the header `Accept: application/vnd.olrapi.note+json`, will return a JSON representation of your note including parsed tag and frontmatter data as well as filesystem metadata. See "responses" below for details.\n',
169+
description: 'Returns the content of the file at the specified path in your vault should the file exist.\n\nContent format options via Accept header:\n- `Accept: application/vnd.olrapi.note+json` - Returns a JSON representation including parsed tag and frontmatter data as well as filesystem metadata\n- `Accept: application/vnd.olrapi.note+html` - Returns rendered HTML from markdown files\n- Default - Returns raw file content\n\nSee "responses" below for details.\n',
170170
parameters+: [ParamPath],
171171
},
172172
put: Put {

src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export enum ContentTypes {
5151
json = "application/json",
5252
markdown = "text/markdown",
5353
olrapiNoteJson = "application/vnd.olrapi.note+json",
54+
olrapiNoteHtml = "application/vnd.olrapi.note+html",
5455
jsonLogic = "application/vnd.olrapi.jsonlogic+json",
5556
dataviewDql = "application/vnd.olrapi.dataview.dql+txt",
5657
}

src/requestHandler.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
App,
44
CachedMetadata,
55
Command,
6+
Component,
7+
MarkdownRenderer,
68
PluginManifest,
79
prepareSimpleSearch,
810
TFile,
@@ -205,6 +207,30 @@ export default class RequestHandler {
205207
};
206208
}
207209

210+
async renderMarkdownToHtml(
211+
markdown: string,
212+
sourcePath: string
213+
): Promise<string> {
214+
const component = new Component();
215+
component.load();
216+
217+
// Create a temporary div to render into
218+
const renderDiv = document.createElement("div");
219+
220+
await MarkdownRenderer.render(
221+
this.app,
222+
markdown,
223+
renderDiv,
224+
sourcePath,
225+
component
226+
);
227+
228+
const html = renderDiv.innerHTML;
229+
component.unload();
230+
231+
return html;
232+
}
233+
208234
getResponseMessage({
209235
statusCode = 400,
210236
message,
@@ -329,6 +355,23 @@ export default class RequestHandler {
329355
return;
330356
}
331357

358+
if (req.headers.accept === ContentTypes.olrapiNoteHtml) {
359+
const file = this.app.vault.getAbstractFileByPath(path) as TFile;
360+
if (file && mimeType === ContentTypes.markdown) {
361+
const markdown = await this.app.vault.cachedRead(file);
362+
const html = await this.renderMarkdownToHtml(markdown, path);
363+
res.setHeader("Content-Type", ContentTypes.olrapiNoteHtml);
364+
res.send(html);
365+
return;
366+
} else {
367+
this.returnCannedResponse(res, {
368+
statusCode: 400,
369+
message: "Rendered HTML is only available for markdown files",
370+
});
371+
return;
372+
}
373+
}
374+
332375
res.send(Buffer.from(content));
333376
} else {
334377
this.returnCannedResponse(res, {

0 commit comments

Comments
 (0)