From 43ef563ae73fac311d59bd1b337660a38fcf782f Mon Sep 17 00:00:00 2001 From: Max Richter Date: Wed, 21 Jan 2026 17:08:47 +0100 Subject: [PATCH] feat: show all nodes in add menu --- .../graph-interface/graph-manager.svelte.ts | 22 ++++++++- packages/registry/src/node-registry-client.ts | 46 ++++++++++--------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index b47a664..d0134d7 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -1,4 +1,5 @@ import throttle from '$lib/helpers/throttle'; +import { RemoteNodeRegistry } from '@nodarium/registry'; import type { Edge, Graph, @@ -18,6 +19,8 @@ import { HistoryManager } from './history-manager'; const logger = createLogger('graph-manager'); logger.mute(); +const remoteRegistry = new RemoteNodeRegistry(''); + const clone = 'structuredClone' in self ? self.structuredClone : (args: any) => JSON.parse(JSON.stringify(args)); @@ -173,7 +176,9 @@ export class GraphManager extends EventEmitter<{ return areSocketsCompatible(edgeOutputSocketType, accepted); }); - const bestOutputIdx = draggedOutputs.findIndex(outputType => areSocketsCompatible(outputType, targetAcceptedTypes)); + const bestOutputIdx = draggedOutputs.findIndex(outputType => + areSocketsCompatible(outputType, targetAcceptedTypes) + ); if (!bestInputEntry || bestOutputIdx === -1) { logger.error('Could not find compatible sockets for drop'); @@ -308,6 +313,21 @@ export class GraphManager extends EventEmitter<{ const nodeIds = Array.from(new Set([...graph.nodes.map((n) => n.type)])); await this.registry.load(nodeIds); + // Fetch all nodes from all collections of the loaded nodes + const allCollections = new Set<`${string}/${string}`>(); + for (const id of nodeIds) { + const [user, collection] = id.split('/'); + allCollections.add(`${user}/${collection}`); + } + for (const collection of allCollections) { + remoteRegistry + .fetchCollection(collection) + .then((collection: { nodes: { id: NodeId }[] }) => { + const ids = collection.nodes.map((n) => n.id); + return this.registry.load(ids); + }); + } + logger.info('loaded node types', this.registry.getAllNodes()); for (const node of this.graph.nodes) { diff --git a/packages/registry/src/node-registry-client.ts b/packages/registry/src/node-registry-client.ts index 464b6ac..a316f86 100644 --- a/packages/registry/src/node-registry-client.ts +++ b/packages/registry/src/node-registry-client.ts @@ -1,32 +1,31 @@ import { - NodeDefinitionSchema, type AsyncCache, type NodeDefinition, - type NodeRegistry, -} from "@nodarium/types"; -import { createLogger, createWasmWrapper } from "@nodarium/utils"; + NodeDefinitionSchema, + type NodeRegistry +} from '@nodarium/types'; +import { createLogger, createWasmWrapper } from '@nodarium/utils'; -const log = createLogger("node-registry"); +const log = createLogger('node-registry'); log.mute(); export class RemoteNodeRegistry implements NodeRegistry { - status: "loading" | "ready" | "error" = "loading"; + status: 'loading' | 'ready' | 'error' = 'loading'; private nodes: Map = new Map(); constructor( private url: string, - public cache?: AsyncCache, + public cache?: AsyncCache ) { } async fetchJson(url: string, skipCache = false) { - const finalUrl = `${this.url}/${url}`; if (!skipCache && this.cache) { const cachedValue = await this.cache?.get(finalUrl); if (cachedValue) { // fetch again in the background, maybe implement that only refetch after a certain time - this.fetchJson(url, true) + this.fetchJson(url, true); return JSON.parse(cachedValue); } } @@ -46,14 +45,13 @@ export class RemoteNodeRegistry implements NodeRegistry { } async fetchArrayBuffer(url: string, skipCache = false) { - const finalUrl = `${this.url}/${url}`; if (!skipCache && this.cache) { const cachedNode = await this.cache?.get(finalUrl); if (cachedNode) { // fetch again in the background, maybe implement that only refetch after a certain time - this.fetchArrayBuffer(url, true) + this.fetchArrayBuffer(url, true); return cachedNode; } } @@ -79,7 +77,7 @@ export class RemoteNodeRegistry implements NodeRegistry { async fetchCollection(userCollectionId: `${string}/${string}`) { const col = await this.fetchJson(`nodes/${userCollectionId}.json`); - return col + return col; } async fetchNodeDefinition(nodeId: `${string}/${string}/${string}`) { @@ -87,7 +85,6 @@ export class RemoteNodeRegistry implements NodeRegistry { } private async fetchNodeWasm(nodeId: `${string}/${string}/${string}`) { - const node = await this.fetchArrayBuffer(`nodes/${nodeId}.wasm`); if (!node) { throw new Error(`Failed to load node wasm ${nodeId}`); @@ -99,7 +96,7 @@ export class RemoteNodeRegistry implements NodeRegistry { async load(nodeIds: `${string}/${string}/${string}`[]) { const a = performance.now(); - const nodes = await Promise.all( + const nodes = (await Promise.all( [...new Set(nodeIds).values()].map(async (id) => { if (this.nodes.has(id)) { return this.nodes.get(id)!; @@ -107,17 +104,23 @@ export class RemoteNodeRegistry implements NodeRegistry { const wasmBuffer = await this.fetchNodeWasm(id); - return this.register(wasmBuffer); - }), - ); + try { + return await this.register(wasmBuffer); + } catch (e) { + console.log('Failed to register: ', id); + console.error(e); + return; + } + }) + )).filter(Boolean) as NodeDefinition[]; const duration = performance.now() - a; - log.group("loaded nodes in", duration, "ms"); + log.group('loaded nodes in', duration, 'ms'); log.info(nodeIds); log.info(nodes); log.groupEnd(); - this.status = "ready"; + this.status = 'ready'; return nodes; } @@ -128,17 +131,16 @@ export class RemoteNodeRegistry implements NodeRegistry { const definition = NodeDefinitionSchema.safeParse(wrapper.get_definition()); if (definition.error) { - console.error(definition.error); throw definition.error; } if (this.cache) { - await this.cache.set(definition.data.id, wasmBuffer); + this.cache.set(definition.data.id, wasmBuffer); } let node = { ...definition.data, - execute: wrapper.execute, + execute: wrapper.execute }; this.nodes.set(definition.data.id, node);