diff --git a/apps/website/src/utils/cloudNodes.test.ts b/apps/website/src/utils/cloudNodes.test.ts index 9b96cc3dd9..01028cbe51 100644 --- a/apps/website/src/utils/cloudNodes.test.ts +++ b/apps/website/src/utils/cloudNodes.test.ts @@ -345,6 +345,53 @@ describe('fetchCloudNodesForBuild', () => { ) }) + it('queries every raw-id alias when packs collide on the same slug and picks the first hit', async () => { + fetchRegistryPacksMock.mockResolvedValue( + new Map([ + ['ComfyUI-QwenVL', null], + [ + 'ComfyUI_QwenVL', + { + id: 'ComfyUI_QwenVL', + name: 'ComfyUI QwenVL', + repository: 'https://github.com/example/ComfyUI_QwenVL' + } + ] + ]) + ) + + const fetchImpl = vi.fn(async () => + response({ + QwenDash: validNode({ + name: 'QwenDash', + python_module: 'custom_nodes.ComfyUI-QwenVL.nodes' + }), + QwenUnder: validNode({ + name: 'QwenUnder', + python_module: 'custom_nodes.ComfyUI_QwenVL.nodes' + }) + }) + ) + const outcome = await fetchCloudNodesForBuild({ + apiKey: KEY, + baseUrl: BASE_URL, + fetchImpl: fetchImpl as typeof fetch + }) + + expect(outcome.status).toBe('fresh') + if (outcome.status !== 'fresh') return + expect(outcome.snapshot.packs).toHaveLength(1) + expect(outcome.snapshot.packs[0]?.id).toBe('comfyui-qwenvl') + expect(outcome.snapshot.packs[0]?.registryId).toBe('ComfyUI_QwenVL') + expect(outcome.snapshot.packs[0]?.repoUrl).toBe( + 'https://github.com/example/ComfyUI_QwenVL' + ) + expect(fetchRegistryPacksMock).toHaveBeenCalledWith( + ['ComfyUI-QwenVL', 'ComfyUI_QwenVL'], + expect.anything() + ) + }) + it('normalizes pack ids when reading a fallback snapshot', async () => { const snapshotUrl = withSnapshotDir({ fetchedAt: '2026-04-01T00:00:00.000Z', diff --git a/apps/website/src/utils/cloudNodes.ts b/apps/website/src/utils/cloudNodes.ts index 2947c2ae8d..2d059c4224 100644 --- a/apps/website/src/utils/cloudNodes.ts +++ b/apps/website/src/utils/cloudNodes.ts @@ -238,12 +238,12 @@ async function parseCloudNodes( ) const grouped = groupNodesByPack(sanitizedDefs) + const allAliases = grouped.flatMap((pack) => pack.rawIds) let registryMap = new Map() try { - registryMap = await fetchRegistryPacks( - grouped.map((pack) => pack.rawId), - { fetchImpl: options.fetchImpl } - ) + registryMap = await fetchRegistryPacks(allAliases, { + fetchImpl: options.fetchImpl + }) } catch { registryMap = new Map() } @@ -253,13 +253,24 @@ async function parseCloudNodes( pack.id, pack.displayName, pack.nodes, - registryMap.get(pack.rawId) + pickRegistryPack(registryMap, pack.rawIds) ) ) return { kind: 'ok', packs, droppedNodes } } +function pickRegistryPack( + registryMap: Map, + aliases: readonly string[] +): RegistryPack | null | undefined { + for (const alias of aliases) { + const hit = registryMap.get(alias) + if (hit) return hit + } + return registryMap.get(aliases[0]) +} + function safeExternalUrl(value: string | undefined): string | undefined { if (!value) return undefined try { diff --git a/packages/object-info-parser/src/__tests__/groupNodesByPack.test.ts b/packages/object-info-parser/src/__tests__/groupNodesByPack.test.ts index fcf2b678b8..ac977f13a1 100644 --- a/packages/object-info-parser/src/__tests__/groupNodesByPack.test.ts +++ b/packages/object-info-parser/src/__tests__/groupNodesByPack.test.ts @@ -92,6 +92,17 @@ describe('groupNodesByPack', () => { 'QwenA', 'QwenB' ]) + expect(grouped[0].rawIds).toEqual(['ComfyUI-QwenVL', 'ComfyUI_QwenVL']) + }) + + it('does not record duplicate aliases when the same raw id appears twice', () => { + const grouped = groupNodesByPack({ + QwenA: makeNodeDef('QwenA', 'custom_nodes.ComfyUI-QwenVL.nodes'), + QwenB: makeNodeDef('QwenB', 'custom_nodes.ComfyUI-QwenVL.nodes') + }) + + expect(grouped).toHaveLength(1) + expect(grouped[0].rawIds).toEqual(['ComfyUI-QwenVL']) }) it('strips version suffix before slugifying', () => { diff --git a/packages/object-info-parser/src/helpers/groupNodesByPack.ts b/packages/object-info-parser/src/helpers/groupNodesByPack.ts index fbee637755..b9073060a9 100644 --- a/packages/object-info-parser/src/helpers/groupNodesByPack.ts +++ b/packages/object-info-parser/src/helpers/groupNodesByPack.ts @@ -10,6 +10,7 @@ export interface PackedNode { export interface NodePack { id: string rawId: string + rawIds: string[] displayName: string nodes: PackedNode[] } @@ -40,12 +41,16 @@ export function groupNodesByPack( if (existing) { existing.nodes.push(node) + if (!existing.rawIds.includes(rawId)) { + existing.rawIds.push(rawId) + } continue } byPackId.set(slug, { id: slug, rawId, + rawIds: [rawId], displayName: source.displayText, nodes: [node] })