Handle HTML fallbacks for node help and skip blueprint docs (#7021)

explicitly prevents subgraphs from making an api call since they don't
have docs, this was previously reliant on a non-ok resolution

also doesn't try returning anything that has contenttype of text/html to
prevent the markdown renderer from crashing

## Summary
- short-circuit blueprint/subgraph nodes in help: skip doc fetch and
return the node description, avoiding SPA fallback responses
- guard node help fetch against HTML/SPA fallbacks using content-type
checks; treat them as missing and trigger the existing description
fallback
- keep base URL logic unchanged for non-blueprint nodes

## Testing
- pnpm typecheck
- pnpm lint:fix
- pnpm test:unit
This commit is contained in:
Benjamin Lu
2025-11-28 10:09:09 -08:00
committed by GitHub
parent fe47a487bb
commit d94e0720f3
2 changed files with 44 additions and 16 deletions

View File

@@ -7,6 +7,10 @@ class NodeHelpService {
async fetchNodeHelp(node: ComfyNodeDefImpl, locale: string): Promise<string> {
const nodeSource = getNodeSource(node.python_module)
if (nodeSource.type === NodeSourceType.Blueprint) {
return node.description || ''
}
if (nodeSource.type === NodeSourceType.CustomNodes) {
return this.fetchCustomNodeHelp(node, locale)
} else {
@@ -19,25 +23,24 @@ class NodeHelpService {
locale: string
): Promise<string> {
const customNodeName = extractCustomNodeName(node.python_module)
let lastError: string | undefined
if (!customNodeName) {
throw new Error('Invalid custom node module')
}
// Try locale-specific path first
const localePath = `/extensions/${customNodeName}/docs/${node.name}/${locale}.md`
let res = await fetch(api.fileURL(localePath))
const localeDoc = await this.tryFetchMarkdown(localePath)
if (localeDoc.text) return localeDoc.text
lastError = localeDoc.errorText
if (!res.ok) {
// Fall back to non-locale path
const fallbackPath = `/extensions/${customNodeName}/docs/${node.name}.md`
res = await fetch(api.fileURL(fallbackPath))
}
// Fall back to non-locale path
const fallbackPath = `/extensions/${customNodeName}/docs/${node.name}.md`
const fallbackDoc = await this.tryFetchMarkdown(fallbackPath)
if (fallbackDoc.text) return fallbackDoc.text
lastError = fallbackDoc.errorText ?? lastError
if (!res.ok) {
throw new Error(res.statusText)
}
return res.text()
throw new Error(lastError ?? 'Help not found')
}
private async fetchCoreNodeHelp(
@@ -45,13 +48,35 @@ class NodeHelpService {
locale: string
): Promise<string> {
const mdUrl = `/docs/${node.name}/${locale}.md`
const res = await fetch(api.fileURL(mdUrl))
if (!res.ok) {
throw new Error(res.statusText)
const doc = await this.tryFetchMarkdown(mdUrl)
if (!doc.text) {
throw new Error(doc.errorText ?? 'Help not found')
}
return res.text()
return doc.text
}
/**
* Fetch a markdown file and return its text, guarding against HTML/SPA fallbacks.
* Returns null when not OK or when the content type indicates HTML.
*/
private async tryFetchMarkdown(
path: string
): Promise<{ text: string | null; errorText?: string }> {
const res = await fetch(api.fileURL(path))
if (!res.ok) {
return { text: null, errorText: res.statusText }
}
const contentType = res.headers?.get?.('content-type') ?? ''
const text = await res.text()
const isHtmlContentType = contentType.includes('text/html')
if (isHtmlContentType) return { text: null, errorText: res.statusText }
return { text }
}
}

View File

@@ -15,6 +15,9 @@ export function extractCustomNodeName(
export function getNodeHelpBaseUrl(node: ComfyNodeDefImpl): string {
const nodeSource = getNodeSource(node.python_module)
if (nodeSource.type === NodeSourceType.Blueprint) {
return ''
}
if (nodeSource.type === NodeSourceType.CustomNodes) {
const customNodeName = extractCustomNodeName(node.python_module)
if (customNodeName) {