From 78c88e4d660c13654587bd51e5eb0689ec34b5b1 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Sat, 20 Apr 2024 02:41:18 +0200 Subject: [PATCH] feat: node store interface --- app/src/lib/graph-interface/graph-manager.ts | 16 +- .../lib/graph-interface/graph/Graph.svelte | 33 ++- .../lib/graph-interface/graph/Wrapper.svelte | 2 +- app/src/lib/graph-interface/node/Node.svelte | 70 +----- .../lib/graph-interface/node/NodeHTML.svelte | 86 ++++++++ .../graph-interface/node/NodeHeader.svelte | 4 +- .../lib/graph-interface/node/NodeInput.svelte | 6 +- .../graph-interface/node/NodeParameter.svelte | 10 +- app/src/lib/helpers/createKeyMap.ts | 28 ++- app/src/lib/node-registry-client.ts | 93 ++++++++ app/src/lib/node-registry.ts | 199 ++++++++---------- app/src/lib/node-store/BreadCrumbs.svelte | 81 +++++++ app/src/lib/node-store/DraggableNode.svelte | 74 +++++++ app/src/lib/node-store/NodeStore.svelte | 92 ++++++++ app/src/lib/node-store/Spinner.svelte | 31 +++ .../{viewer => result-viewer}/Scene.svelte | 0 .../{viewer => result-viewer}/Viewer.svelte | 0 app/src/lib/settings/Keymap.svelte | 17 +- app/src/lib/settings/NodeStore.svelte | 0 app/src/lib/settings/Settings.svelte | 2 +- app/src/routes/+layout.server.ts | 1 + app/src/routes/+layout.svelte | 4 - app/src/routes/+page.svelte | 27 ++- app/src/routes/nodes/[user].json/+server.ts | 22 ++ .../nodes/[user]/[collection].json/+server.ts | 22 ++ .../[collection]/[node].json/+server.ts | 31 +++ .../[collection]/[node].wasm/+server.ts | 27 +++ app/src/routes/nodes/users.json/+server.ts | 14 ++ packages/node-registry/.eslintignore | 13 -- packages/node-registry/.eslintrc.cjs | 31 --- packages/node-registry/.gitignore | 10 - packages/node-registry/.npmrc | 1 - packages/node-registry/.prettierignore | 4 - packages/node-registry/.prettierrc | 8 - packages/node-registry/README.md | 38 ---- packages/node-registry/package.json | 40 ---- packages/node-registry/src/app.d.ts | 13 -- packages/node-registry/src/app.html | 12 -- packages/node-registry/src/lib/index.ts | 1 - packages/node-registry/src/lib/registry.ts | 32 --- .../node-registry/src/routes/+page.svelte | 2 - .../n/[user]/[collection]/[node]/+server.ts | 17 -- .../[collection]/[node]/test/+page.svelte | 27 --- .../[user]/[collection]/[node]/test/+page.ts | 7 - .../[collection]/[node]/wasm/+server.ts | 20 -- packages/node-registry/static/favicon.ico | Bin 5430 -> 0 bytes packages/node-registry/static/favicon.png | Bin 1571 -> 0 bytes packages/node-registry/svelte.config.js | 20 -- packages/node-registry/tsconfig.json | 19 -- packages/node-registry/vite.config.ts | 14 -- packages/types/src/index.ts | 3 +- 51 files changed, 772 insertions(+), 552 deletions(-) create mode 100644 app/src/lib/graph-interface/node/NodeHTML.svelte create mode 100644 app/src/lib/node-registry-client.ts create mode 100644 app/src/lib/node-store/BreadCrumbs.svelte create mode 100644 app/src/lib/node-store/DraggableNode.svelte create mode 100644 app/src/lib/node-store/NodeStore.svelte create mode 100644 app/src/lib/node-store/Spinner.svelte rename app/src/lib/{viewer => result-viewer}/Scene.svelte (100%) rename app/src/lib/{viewer => result-viewer}/Viewer.svelte (100%) delete mode 100644 app/src/lib/settings/NodeStore.svelte create mode 100644 app/src/routes/+layout.server.ts create mode 100644 app/src/routes/nodes/[user].json/+server.ts create mode 100644 app/src/routes/nodes/[user]/[collection].json/+server.ts create mode 100644 app/src/routes/nodes/[user]/[collection]/[node].json/+server.ts create mode 100644 app/src/routes/nodes/[user]/[collection]/[node].wasm/+server.ts create mode 100644 app/src/routes/nodes/users.json/+server.ts delete mode 100644 packages/node-registry/.eslintignore delete mode 100644 packages/node-registry/.eslintrc.cjs delete mode 100644 packages/node-registry/.gitignore delete mode 100644 packages/node-registry/.npmrc delete mode 100644 packages/node-registry/.prettierignore delete mode 100644 packages/node-registry/.prettierrc delete mode 100644 packages/node-registry/README.md delete mode 100644 packages/node-registry/package.json delete mode 100644 packages/node-registry/src/app.d.ts delete mode 100644 packages/node-registry/src/app.html delete mode 100644 packages/node-registry/src/lib/index.ts delete mode 100644 packages/node-registry/src/lib/registry.ts delete mode 100644 packages/node-registry/src/routes/+page.svelte delete mode 100644 packages/node-registry/src/routes/n/[user]/[collection]/[node]/+server.ts delete mode 100644 packages/node-registry/src/routes/n/[user]/[collection]/[node]/test/+page.svelte delete mode 100644 packages/node-registry/src/routes/n/[user]/[collection]/[node]/test/+page.ts delete mode 100644 packages/node-registry/src/routes/n/[user]/[collection]/[node]/wasm/+server.ts delete mode 100644 packages/node-registry/static/favicon.ico delete mode 100644 packages/node-registry/static/favicon.png delete mode 100644 packages/node-registry/svelte.config.js delete mode 100644 packages/node-registry/tsconfig.json delete mode 100644 packages/node-registry/vite.config.ts diff --git a/app/src/lib/graph-interface/graph-manager.ts b/app/src/lib/graph-interface/graph-manager.ts index 4c6636b..2f8604f 100644 --- a/app/src/lib/graph-interface/graph-manager.ts +++ b/app/src/lib/graph-interface/graph-manager.ts @@ -36,7 +36,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, " history: HistoryManager = new HistoryManager(); - constructor(private nodeRegistry: NodeRegistry) { + constructor(public registry: NodeRegistry) { super(); this.nodes.subscribe((nodes) => { this._nodes = nodes; @@ -82,7 +82,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, " } getNodeTypes() { - return this.nodeRegistry.getAllNodes(); + return this.registry.getAllNodes(); } getLinkedNodes(node: Node) { @@ -122,7 +122,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, " private _init(graph: Graph) { const nodes = new Map(graph.nodes.map(node => { - const nodeType = this.nodeRegistry.getNode(node.type); + const nodeType = this.registry.getNode(node.type); if (nodeType) { node.tmp = { random: (Math.random() - 0.5) * 2, @@ -164,10 +164,10 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, " this.id.set(graph.id); const nodeIds = Array.from(new Set([...graph.nodes.map(n => n.type)])); - await this.nodeRegistry.load(nodeIds); + await this.registry.load(nodeIds); for (const node of this.graph.nodes) { - const nodeType = this.nodeRegistry.getNode(node.type); + const nodeType = this.registry.getNode(node.type); if (!nodeType) { logger.error(`Node type not found: ${node.type}`); this.status.set("error"); @@ -222,7 +222,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, " } getNodeType(id: string) { - return this.nodeRegistry.getNode(id); + return this.registry.getNode(id); } getChildrenOfNode(node: Node) { @@ -303,7 +303,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, " nodes = nodes.map((node, i) => { const id = startId + i; idMap.set(node.id, id); - const type = this.nodeRegistry.getNode(node.type); + const type = this.registry.getNode(node.type); if (!type) { throw new Error(`Node type not found: ${node.type}`); } @@ -343,7 +343,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, " createNode({ type, position, props = {} }: { type: Node["type"], position: Node["position"], props: Node["props"] }) { - const nodeType = this.nodeRegistry.getNode(type); + const nodeType = this.registry.getNode(type); if (!nodeType) { logger.error(`Node type not found: ${type}`); return; diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index dcde950..6496788 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -20,6 +20,7 @@ import { createKeyMap } from "../../helpers/createKeyMap"; import BoxSelection from "../BoxSelection.svelte"; import AddMenu from "../AddMenu.svelte"; + import { get } from "svelte/store"; export let graph: GraphManager; @@ -78,7 +79,7 @@ } function updateNodePosition(node: NodeType) { - if (node?.tmp?.ref) { + if (node?.tmp?.ref && node?.tmp?.mesh) { if (node.tmp["x"] !== undefined && node.tmp["y"] !== undefined) { node.tmp.ref.style.setProperty("--nx", `${node.tmp.x * 10}px`); node.tmp.ref.style.setProperty("--ny", `${node.tmp.y * 10}px`); @@ -758,6 +759,34 @@ addMenuPosition = null; } + function handleDrop(event: DragEvent) { + if (!event.dataTransfer) return; + const nodeId = event.dataTransfer.getData("data/node-id"); + let mx = event.clientX - rect.x; + let my = event.clientY - rect.y; + + let nodeOffsetX = event.dataTransfer.getData("data/node-offset-x"); + let nodeOffsetY = event.dataTransfer.getData("data/node-offset-y"); + if (nodeOffsetX && nodeOffsetY) { + mx += parseInt(nodeOffsetX); + my += parseInt(nodeOffsetY); + } + + const pos = projectScreenToWorld(mx, my); + graph.registry.load([nodeId]).then(() => { + graph.createNode({ + type: nodeId, + props: {}, + position: pos, + }); + }); + console.log({ nodeId }); + } + + function handlerDragOver(e: DragEvent) { + e.preventDefault(); + } + onMount(() => { if (localStorage.getItem("cameraPosition")) { const cPosition = JSON.parse(localStorage.getItem("cameraPosition")!); @@ -779,6 +808,8 @@ tabindex="0" bind:clientWidth={width} bind:clientHeight={height} + on:dragover={handlerDragOver} + on:drop={handleDrop} on:keydown={keymap.handleKeyboardEvent} on:mousedown={handleMouseDown} > diff --git a/app/src/lib/graph-interface/graph/Wrapper.svelte b/app/src/lib/graph-interface/graph/Wrapper.svelte index 27d3380..9adf484 100644 --- a/app/src/lib/graph-interface/graph/Wrapper.svelte +++ b/app/src/lib/graph-interface/graph/Wrapper.svelte @@ -11,7 +11,7 @@ export let graph: Graph; export let settings: Writable> | undefined; - const manager = new GraphManager(registry); + export const manager = new GraphManager(registry); export const status = manager.status; diff --git a/app/src/lib/graph-interface/node/Node.svelte b/app/src/lib/graph-interface/node/Node.svelte index dd4f57f..037d6c6 100644 --- a/app/src/lib/graph-interface/node/Node.svelte +++ b/app/src/lib/graph-interface/node/Node.svelte @@ -9,6 +9,7 @@ import { Color, type Mesh } from "three"; import NodeFrag from "./Node.frag"; import NodeVert from "./Node.vert"; + import NodeHtml from "./NodeHTML.svelte"; export let node: Node; export let inView = true; @@ -22,32 +23,20 @@ const getNodeHeight = getContext<(n: string) => number>("getNodeHeight"); - const type = node?.tmp?.type; - - const zOffset = (node.tmp?.random || 0) * 0.5; - const zLimit = 2 - zOffset; - - const parameters = Object.entries(type?.inputs || {}) - .filter((p) => p[1].type !== "seed") - .filter((p) => !("setting" in p[1])); - - let ref: HTMLDivElement; let meshRef: Mesh; - const height = getNodeHeight(node.type); + const height = getNodeHeight?.(node.type); - $: if (node && ref && meshRef) { + $: if (node && meshRef) { node.tmp = node.tmp || {}; - node.tmp.ref = ref; node.tmp.mesh = meshRef; - updateNodePosition(node); + updateNodePosition?.(node); } onMount(() => { node.tmp = node.tmp || {}; - node.tmp.ref = ref; node.tmp.mesh = meshRef; - updateNodePosition(node); + updateNodePosition?.(node); }); @@ -83,51 +72,4 @@ /> -
zLimit ? "block" : "none"} - class:selected={isSelected} - class:out-of-view={!inView} - data-node-id={node.id} - bind:this={ref} -> - - - {#each parameters as [key, value], i} - - {/each} -
- - + diff --git a/app/src/lib/graph-interface/node/NodeHTML.svelte b/app/src/lib/graph-interface/node/NodeHTML.svelte new file mode 100644 index 0000000..34f68a6 --- /dev/null +++ b/app/src/lib/graph-interface/node/NodeHTML.svelte @@ -0,0 +1,86 @@ + + +
zLimit ? "block" : "none"} + class:selected={isSelected} + class:out-of-view={!inView} + data-node-id={node.id} + bind:this={ref} +> + + + {#each parameters as [key, value], i} + + {/each} +
+ + diff --git a/app/src/lib/graph-interface/node/NodeHeader.svelte b/app/src/lib/graph-interface/node/NodeHeader.svelte index 95987da..182a8de 100644 --- a/app/src/lib/graph-interface/node/NodeHeader.svelte +++ b/app/src/lib/graph-interface/node/NodeHeader.svelte @@ -14,10 +14,10 @@ function handleMouseDown(event: MouseEvent) { event.stopPropagation(); event.preventDefault(); - setDownSocket({ + setDownSocket?.({ node, index: 0, - position: getSocketPosition(node, 0), + position: getSocketPosition?.(node, 0), }); } diff --git a/app/src/lib/graph-interface/node/NodeInput.svelte b/app/src/lib/graph-interface/node/NodeInput.svelte index ebc6a32..fad3fb8 100644 --- a/app/src/lib/graph-interface/node/NodeInput.svelte +++ b/app/src/lib/graph-interface/node/NodeInput.svelte @@ -15,8 +15,10 @@ $: if (node?.props?.[id] !== value) { node.props = { ...node.props, [id]: value }; - graph.save(); - graph.execute(); + if (graph) { + graph.save(); + graph.execute(); + } } diff --git a/app/src/lib/graph-interface/node/NodeParameter.svelte b/app/src/lib/graph-interface/node/NodeParameter.svelte index 720f796..46d5772 100644 --- a/app/src/lib/graph-interface/node/NodeParameter.svelte +++ b/app/src/lib/graph-interface/node/NodeParameter.svelte @@ -20,8 +20,8 @@ const socketId = `${node.id}-${id}`; const graph = getGraphManager(); - const graphId = graph.id; - const inputSockets = graph.inputSockets; + const graphId = graph?.id; + const inputSockets = graph?.inputSockets; const elementId = `input-${Math.random().toString(36).substring(7)}`; @@ -34,10 +34,10 @@ function handleMouseDown(ev: MouseEvent) { ev.preventDefault(); ev.stopPropagation(); - setDownSocket({ + setDownSocket?.({ node, index: id, - position: getSocketPosition(node, id), + position: getSocketPosition?.(node, id), }); } @@ -76,7 +76,7 @@ class:disabled={$possibleSocketIds && !$possibleSocketIds.has(socketId)} > {#key id && graphId} -
+
{#if inputType.label !== false} {/if} diff --git a/app/src/lib/helpers/createKeyMap.ts b/app/src/lib/helpers/createKeyMap.ts index 00e5846..f9cc3c9 100644 --- a/app/src/lib/helpers/createKeyMap.ts +++ b/app/src/lib/helpers/createKeyMap.ts @@ -1,4 +1,4 @@ -import { get, writable } from "svelte/store"; +import { derived, get, writable } from "svelte/store"; type Shortcut = { key: string | string[], @@ -9,35 +9,45 @@ type Shortcut = { callback: (event: KeyboardEvent) => void } +function getShortcutId(shortcut: Shortcut) { + return `${shortcut.key}${shortcut.shift ? "+shift" : ""}${shortcut.ctrl ? "+ctrl" : ""}${shortcut.alt ? "+alt" : ""}`; +} + export function createKeyMap(keys: Shortcut[]) { - const store = writable(keys); + const store = writable(new Map(keys.map(k => [getShortcutId(k), k]))); return { handleKeyboardEvent: (event: KeyboardEvent) => { - const key = get(store).find(k => { + const key = [...get(store).values()].find(k => { if (Array.isArray(k.key) ? !k.key.includes(event.key) : k.key !== event.key) return false; if ("shift" in k && k.shift !== event.shiftKey) return false; if ("ctrl" in k && k.ctrl !== event.ctrlKey) return false; if ("alt" in k && k.alt !== event.altKey) return false; return true; }); - console.log({ keys: get(store), out: key, key: event.key }); key?.callback(event); }, addShortcut: (shortcut: Shortcut) => { if (Array.isArray(shortcut.key)) { for (const k of shortcut.key) { - store.update(keys => { - if (keys.find(kk => kk.key === k)) return keys; - return [...keys, { ...shortcut, key: k }]; + store.update(shortcuts => { + const id = getShortcutId({ ...shortcut, key: k }); + shortcuts.delete(id); + shortcuts.set(id, { ...shortcut, key: k }); + return shortcuts; }); } } else { - store.update(keys => [...keys, shortcut]); + store.update(shortcuts => { + const id = getShortcutId(shortcut); + shortcuts.delete(id); + shortcuts.set(id, shortcut); + return shortcuts; + }); } }, - keys: store + keys: derived(store, $store => Array.from($store.values())) } } diff --git a/app/src/lib/node-registry-client.ts b/app/src/lib/node-registry-client.ts new file mode 100644 index 0000000..35af521 --- /dev/null +++ b/app/src/lib/node-registry-client.ts @@ -0,0 +1,93 @@ +import type { NodeRegistry, NodeType } from "@nodes/types"; +import { createWasmWrapper } from "@nodes/utils"; +import { createLogger } from "./helpers"; + +const log = createLogger("node-registry"); +export class RemoteNodeRegistry implements NodeRegistry { + + status: "loading" | "ready" | "error" = "loading"; + private nodes: Map = new Map(); + + constructor(private url: string) { } + + private async loadNode(id: `${string}/${string}/${string}`) { + const wasmResponse = await this.fetchNode(id); + + // Setup Wasm wrapper + const wrapper = createWasmWrapper(); + const module = new WebAssembly.Module(wasmResponse); + const instance = new WebAssembly.Instance(module, { ["./index_bg.js"]: wrapper }); + wrapper.setInstance(instance); + + const definition = wrapper.get_definition(); + + return { + ...definition, + id, + execute: wrapper.execute + }; + } + + async fetchUsers() { + const response = await fetch(`${this.url}/nodes/users.json`); + if (!response.ok) { + throw new Error(`Failed to load users`); + } + return response.json(); + } + + async fetchUser(userId: `${string}`) { + const response = await fetch(`${this.url}/nodes/${userId}.json`); + if (!response.ok) { + throw new Error(`Failed to load user ${userId}`); + } + return response.json(); + } + + async fetchCollection(userCollectionId: `${string}/${string}`) { + const response = await fetch(`${this.url}/nodes/${userCollectionId}.json`); + if (!response.ok) { + throw new Error(`Failed to load collection ${userCollectionId}`); + } + return response.json(); + } + + async fetchNode(nodeId: `${string}/${string}/${string}`) { + const response = await fetch(`${this.url}/nodes/${nodeId}.wasm`); + if (!response.ok) { + throw new Error(`Failed to load node wasm ${nodeId}`); + } + return response.arrayBuffer(); + } + + async fetchNodeDefinition(nodeId: `${string}/${string}/${string}`) { + const response = await fetch(`${this.url}/nodes/${nodeId}.json`); + if (!response.ok) { + throw new Error(`Failed to load node definition ${nodeId}`); + } + return response.json() + } + + async load(nodeIds: `${string}/${string}/${string}`[]) { + const a = performance.now(); + + const nodes = await Promise.all(nodeIds.map(id => this.loadNode(id))); + + for (const node of nodes) { + this.nodes.set(node.id, node); + } + + const duration = performance.now() - a; + + log.log("loaded nodes in", duration, "ms"); + this.status = "ready"; + } + + getNode(id: string) { + return this.nodes.get(id); + } + + getAllNodes() { + return [...this.nodes.values()]; + } +} diff --git a/app/src/lib/node-registry.ts b/app/src/lib/node-registry.ts index 24b9dc8..4dab055 100644 --- a/app/src/lib/node-registry.ts +++ b/app/src/lib/node-registry.ts @@ -1,120 +1,101 @@ -import type { NodeRegistry, NodeType } from "@nodes/types"; -import { createWasmWrapper } from "@nodes/utils"; +import { createWasmWrapper } from "@nodes/utils" +import fs from "fs/promises" +import path from "path" -import { createLogger } from "./helpers"; +export async function getWasm(id: `${string}/${string}/${string}`) { + const filePath = path.resolve(`../nodes/${id}/pkg/index_bg.wasm`); -const nodeTypes: NodeType[] = [ - { - id: "max/plantarium/float", - inputs: { - "value": { type: "float", value: 0.1, internal: true }, - }, - outputs: ["float"], - execute: (value) => { return value; } - }, - { - id: "max/plantarium/math", - inputs: { - "op_type": { label: "type", type: "select", options: ["add", "subtract", "multiply", "divide"], value: 0 }, - "a": { type: "float" }, - "b": { type: "float" }, - }, - outputs: ["float"], - execute: ([op_type, a, b]: number[]) => { - switch (op_type) { - case 0: return a + b; - case 1: return a - b; - case 2: return a * b; - case 3: return a / b; + try { + await fs.access(filePath); + } catch (e) { + return null + } + + const file = await fs.readFile(filePath); + + const bytes = new Uint8Array(file); + + return bytes; + +} + +export async function getNodeWasm(id: `${string}/${string}/${string}`) { + + const wasmBytes = await getWasm(id); + if (!wasmBytes) return null; + + const wrapper = createWasmWrapper(); + const module = new WebAssembly.Module(wasmBytes); + const instance = new WebAssembly.Instance(module, { ["./index_bg.js"]: wrapper }); + wrapper.setInstance(instance) + + return wrapper; +} + + +export async function getNode(id: `${string}/${string}/${string}`) { + + const wrapper = await getNodeWasm(id); + + const definition = wrapper?.get_definition?.(); + + if (!definition) return null; + + const { inputs, outputs } = definition; + try { + return { id, inputs, outputs } + } catch (e) { + console.log("Failed to parse input types for node", { id }); + } + +} + +export async function getCollectionNodes(userId: `${string}/${string}`) { + const nodes = await fs.readdir(path.resolve(`../nodes/${userId}`)); + return nodes + .filter(n => n !== "pkg" && n !== ".template") + .map(n => { + return { + id: `${userId}/${n}`, } - } - }, - { - id: "max/plantarium/output", - inputs: { - "input": { type: "float" }, - }, - outputs: [], - } -] + }) +} - -const log = createLogger("node-registry"); -export class RemoteNodeRegistry implements NodeRegistry { - - - status: "loading" | "ready" | "error" = "loading"; - private nodes: Map = new Map(); - - constructor(private url: string) { } - - private async loadNode(id: string) { - const nodeUrl = `${this.url}/n/${id}`; - const [response, wasmResponse] = await Promise.all([fetch(nodeUrl), fetch(`${nodeUrl}/wasm`)]); - if (!wasmResponse.ok || !response.ok) { - this.status = "error"; - throw new Error(`Failed to load node ${id}`); - } - - // Setup Wasm wrapper - const wrapper = createWasmWrapper(); - const module = new WebAssembly.Module(await wasmResponse.arrayBuffer()); - const instance = new WebAssembly.Instance(module, { ["./index_bg.js"]: wrapper }); - wrapper.setInstance(instance); - - const node = await response.json(); - node.execute = wrapper.execute; - return node; - } - - async load(nodeIds: string[]) { - const a = performance.now(); - - nodeIds.push("max/plantarium/random"); - nodeIds.push("max/plantarium/float"); - nodeIds.push("max/plantarium/triangle"); - nodeIds.push("max/plantarium/vec3"); - nodeIds.push("max/plantarium/output"); - nodeIds.push("max/plantarium/array"); - nodeIds.push("max/plantarium/sum"); - nodeIds.push("max/plantarium/stem"); - nodeIds.push("max/plantarium/box"); - nodeIds.push("max/plantarium/math"); - - const nodes = await Promise.all(nodeIds.map(id => this.loadNode(id))); - - for (const node of nodes) { - this.nodes.set(node.id, node); - } - - const duration = performance.now() - a; - - log.log("loaded nodes in", duration, "ms"); - this.status = "ready"; - } - - getNode(id: string) { - return this.nodes.get(id); - } - - getAllNodes() { - return [...this.nodes.values()]; +export async function getCollection(userId: `${string}/${string}`) { + const nodes = await getCollectionNodes(userId); + return { + id: userId, + nodes, } } -export class MemoryNodeRegistry implements NodeRegistry { +export async function getUserCollections(userId: string) { + const collections = await fs.readdir(path.resolve(`../nodes/${userId}`)); + return Promise.all(collections.map(async n => { + const nodes = await getCollectionNodes(`${userId}/${n}`); + return { + id: `${userId}/${n}`, + nodes, + } + })); +} - status: "loading" | "ready" | "error" = "ready"; - - async load(nodeIds: string[]) { - // Do nothing - } - - getNode(id: string) { - return nodeTypes.find((nodeType) => nodeType.id === id); - } - getAllNodes() { - return [...nodeTypes]; +export async function getUser(userId: string) { + const collections = await getUserCollections(userId); + return { + id: userId, + collections } } +export async function getUsers() { + const nodes = await fs.readdir(path.resolve("../nodes")); + const users = await Promise.all(nodes.map(async n => { + const collections = await getUserCollections(n); + return { + id: n, + collections + } + })) + return users; +} diff --git a/app/src/lib/node-store/BreadCrumbs.svelte b/app/src/lib/node-store/BreadCrumbs.svelte new file mode 100644 index 0000000..9e2c9fb --- /dev/null +++ b/app/src/lib/node-store/BreadCrumbs.svelte @@ -0,0 +1,81 @@ + + + + + diff --git a/app/src/lib/node-store/DraggableNode.svelte b/app/src/lib/node-store/DraggableNode.svelte new file mode 100644 index 0000000..7b77145 --- /dev/null +++ b/app/src/lib/node-store/DraggableNode.svelte @@ -0,0 +1,74 @@ + + +
+
{ + dragging = false; + }} + draggable={true} + role="button" + tabindex="0" + on:dragstart={handleDragStart} + > + +
+
+ + diff --git a/app/src/lib/node-store/NodeStore.svelte b/app/src/lib/node-store/NodeStore.svelte new file mode 100644 index 0000000..4e52b64 --- /dev/null +++ b/app/src/lib/node-store/NodeStore.svelte @@ -0,0 +1,92 @@ + + + + +
+ {#if !activeUser} +

Users

+ {#await nodeRegistry.fetchUsers()} +
Loading...
+ {:then users} + {#each users as user} + + {/each} + {:catch error} +
{error.message}
+ {/await} + {:else if !activeCollection} + {#await nodeRegistry.fetchUser(activeUser)} +
Loading...
+ {:then user} +

Collections

+ {#each user.collections as collection} + + {/each} + {:catch error} +
{error.message}
+ {/await} + {:else if !activeNode} +

Nodes

+ {#await nodeRegistry.fetchCollection(`${activeUser}/${activeCollection}`)} +
Loading...
+ {:then collection} + {#each collection.nodes as node} + + {/each} + {:catch error} +
{error.message}
+ {/await} + {:else} + {#await nodeRegistry.fetchNodeDefinition(`${activeUser}/${activeCollection}/${activeNode}`)} +
Loading...
+ {:then node} + + {:catch error} +
{error.message}
+ {/await} + {/if} +
+ + diff --git a/app/src/lib/node-store/Spinner.svelte b/app/src/lib/node-store/Spinner.svelte new file mode 100644 index 0000000..7b84e7b --- /dev/null +++ b/app/src/lib/node-store/Spinner.svelte @@ -0,0 +1,31 @@ + + + + + diff --git a/app/src/lib/viewer/Scene.svelte b/app/src/lib/result-viewer/Scene.svelte similarity index 100% rename from app/src/lib/viewer/Scene.svelte rename to app/src/lib/result-viewer/Scene.svelte diff --git a/app/src/lib/viewer/Viewer.svelte b/app/src/lib/result-viewer/Viewer.svelte similarity index 100% rename from app/src/lib/viewer/Viewer.svelte rename to app/src/lib/result-viewer/Viewer.svelte diff --git a/app/src/lib/settings/Keymap.svelte b/app/src/lib/settings/Keymap.svelte index eb1e6de..95b22de 100644 --- a/app/src/lib/settings/Keymap.svelte +++ b/app/src/lib/settings/Keymap.svelte @@ -14,15 +14,15 @@
{#if key.ctrl} - Ctrl + Ctrl + {/if} {#if key.shift} - Shift + Shift {/if} {#if key.alt} - Alt + Alt {/if} - {key.key} + {key.key}

{key.description}

@@ -51,21 +51,18 @@ .command-wrapper { display: flex; - justify-content: left; + justify-content: right; align-items: center; } .command { - background: var(--layer-3); + background: var(--outline); padding: 0.4em; + font-size: 0.8em; border-radius: 0.3em; white-space: nowrap; } - .command > * { - color: var(--layer-0); - } - p { font-size: 0.9em; margin: 0; diff --git a/app/src/lib/settings/NodeStore.svelte b/app/src/lib/settings/NodeStore.svelte deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/lib/settings/Settings.svelte b/app/src/lib/settings/Settings.svelte index 22d217d..d147a17 100644 --- a/app/src/lib/settings/Settings.svelte +++ b/app/src/lib/settings/Settings.svelte @@ -113,7 +113,7 @@ transform 0.2s, background 0.2s ease; width: 30%; - min-width: 300px; + min-width: 350px; } h1 { diff --git a/app/src/routes/+layout.server.ts b/app/src/routes/+layout.server.ts new file mode 100644 index 0000000..189f71e --- /dev/null +++ b/app/src/routes/+layout.server.ts @@ -0,0 +1 @@ +export const prerender = true; diff --git a/app/src/routes/+layout.svelte b/app/src/routes/+layout.svelte index d92b1e7..f6a51ae 100644 --- a/app/src/routes/+layout.svelte +++ b/app/src/routes/+layout.svelte @@ -5,7 +5,3 @@ - -{#if false} - -{/if} diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index 8956baa..2403834 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -2,17 +2,20 @@ import Grid from "$lib/grid"; import GraphInterface from "$lib/graph-interface"; import { MemoryRuntimeExecutor } from "$lib/runtime-executor"; - import { RemoteNodeRegistry } from "$lib/node-registry"; + import { RemoteNodeRegistry } from "$lib/node-registry-client"; import * as templates from "$lib/graph-templates"; import type { Graph } from "@nodes/types"; - import Viewer from "$lib/viewer/Viewer.svelte"; + import Viewer from "$lib/result-viewer/Viewer.svelte"; import Settings from "$lib/settings/Settings.svelte"; import { AppSettings, AppSettingTypes } from "$lib/settings/app-settings"; import { get, writable, type Writable } from "svelte/store"; import Keymap from "$lib/settings/Keymap.svelte"; import type { createKeyMap } from "$lib/helpers/createKeyMap"; + import NodeStore from "$lib/node-store/NodeStore.svelte"; + import type { GraphManager } from "$lib/graph-interface/graph-manager"; + import { setContext } from "svelte"; - const nodeRegistry = new RemoteNodeRegistry("http://localhost:3001"); + const nodeRegistry = new RemoteNodeRegistry(""); const runtimeExecutor = new MemoryRuntimeExecutor(nodeRegistry); let res: Int32Array; @@ -21,7 +24,11 @@ ? JSON.parse(localStorage.getItem("graph")!) : templates.grid(3, 3); + let manager: GraphManager; let managerStatus: Writable<"loading" | "error" | "idle">; + $: if (manager) { + setContext("graphManager", manager); + } let keymap: ReturnType; @@ -41,6 +48,7 @@ definition: AppSettingTypes, }, shortcuts: {}, + nodeStore: {}, graph: {}, }; @@ -53,7 +61,16 @@ }; settings = settings; - console.log({ settings }); + } + + $: if (manager) { + settings.nodeStore = { + id: "Node Store", + icon: "i-tabler-database", + props: { nodeRegistry, manager }, + component: NodeStore, + }; + settings = settings; } function handleSettings( @@ -91,10 +108,10 @@ {#key graph} { + const users = await registry.getUsers(); + return users.map(user => { + return { user: user.id } + }).flat(2); +} + + +export const GET: RequestHandler = async function GET({ params }) { + + const namespaces = await registry.getUser(params.user) + + return json(namespaces); + +} diff --git a/app/src/routes/nodes/[user]/[collection].json/+server.ts b/app/src/routes/nodes/[user]/[collection].json/+server.ts new file mode 100644 index 0000000..7813fa2 --- /dev/null +++ b/app/src/routes/nodes/[user]/[collection].json/+server.ts @@ -0,0 +1,22 @@ +import { json } from "@sveltejs/kit"; +import type { EntryGenerator, RequestHandler } from "./$types"; +import * as registry from "$lib/node-registry"; + +export const prerender = true; + +export const entries: EntryGenerator = async () => { + const users = await registry.getUsers(); + return users.map(user => { + return user.collections.map(collection => { + return { user: user.id, collection: collection.id } + }) + }).flat(2); +} + +export const GET: RequestHandler = async function GET({ params }) { + + const namespaces = await registry.getCollection(`${params.user}/${params.collection}`); + + return json(namespaces); + +} diff --git a/app/src/routes/nodes/[user]/[collection]/[node].json/+server.ts b/app/src/routes/nodes/[user]/[collection]/[node].json/+server.ts new file mode 100644 index 0000000..e44d547 --- /dev/null +++ b/app/src/routes/nodes/[user]/[collection]/[node].json/+server.ts @@ -0,0 +1,31 @@ +import { json } from "@sveltejs/kit"; +import type { EntryGenerator, RequestHandler } from "./$types"; +import { getNode } from "$lib/node-registry"; +import * as registry from "$lib/node-registry"; + +export const prerender = true; + + +export const entries: EntryGenerator = async () => { + const users = await registry.getUsers(); + return users.map(user => { + return user.collections.map(collection => { + return collection.nodes.map(node => { + return { user: user.id, collection: collection.id, node: node.id } + }); + }) + }).flat(2); +} + +export const GET: RequestHandler = async function GET({ params }) { + + const nodeId = `${params.user}/${params.collection}/${params.node}` as const; + + try { + const node = await getNode(nodeId); + return json(node); + } catch (err) { + console.log(err) + return new Response("Not found", { status: 404 }); + } +} diff --git a/app/src/routes/nodes/[user]/[collection]/[node].wasm/+server.ts b/app/src/routes/nodes/[user]/[collection]/[node].wasm/+server.ts new file mode 100644 index 0000000..372f63c --- /dev/null +++ b/app/src/routes/nodes/[user]/[collection]/[node].wasm/+server.ts @@ -0,0 +1,27 @@ +import type { RequestHandler } from "./$types"; +import * as registry from "$lib/node-registry"; +import type { EntryGenerator } from "../$types"; + +export const prerender = true; + +export const entries: EntryGenerator = async () => { + const users = await registry.getUsers(); + return users.map(user => { + return user.collections.map(collection => { + return collection.nodes.map(node => { + return { user: user.id, collection: collection.id, node: node.id } + }); + }) + }).flat(2); +} + +export const GET: RequestHandler = async function GET({ params }) { + + const wasm = await registry.getWasm(`${params.user}/${params.collection}/${params.node}`); + + if (!wasm) { + return new Response("Not found", { status: 404 }); + } + + return new Response(wasm, { status: 200, headers: { "Content-Type": "application/wasm" } }); +} diff --git a/app/src/routes/nodes/users.json/+server.ts b/app/src/routes/nodes/users.json/+server.ts new file mode 100644 index 0000000..fe03ee0 --- /dev/null +++ b/app/src/routes/nodes/users.json/+server.ts @@ -0,0 +1,14 @@ +import { json } from "@sveltejs/kit"; +import type { RequestHandler } from "./$types"; + +import * as registry from "$lib/node-registry"; + +export const prerender = true; + +export const GET: RequestHandler = async function GET() { + + const users = await registry.getUsers(); + + return json(users); + +} diff --git a/packages/node-registry/.eslintignore b/packages/node-registry/.eslintignore deleted file mode 100644 index 3897265..0000000 --- a/packages/node-registry/.eslintignore +++ /dev/null @@ -1,13 +0,0 @@ -.DS_Store -node_modules -/build -/.svelte-kit -/package -.env -.env.* -!.env.example - -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock diff --git a/packages/node-registry/.eslintrc.cjs b/packages/node-registry/.eslintrc.cjs deleted file mode 100644 index 0b75758..0000000 --- a/packages/node-registry/.eslintrc.cjs +++ /dev/null @@ -1,31 +0,0 @@ -/** @type { import("eslint").Linter.Config } */ -module.exports = { - root: true, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:svelte/recommended', - 'prettier' - ], - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], - parserOptions: { - sourceType: 'module', - ecmaVersion: 2020, - extraFileExtensions: ['.svelte'] - }, - env: { - browser: true, - es2017: true, - node: true - }, - overrides: [ - { - files: ['*.svelte'], - parser: 'svelte-eslint-parser', - parserOptions: { - parser: '@typescript-eslint/parser' - } - } - ] -}; diff --git a/packages/node-registry/.gitignore b/packages/node-registry/.gitignore deleted file mode 100644 index 6635cf5..0000000 --- a/packages/node-registry/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.DS_Store -node_modules -/build -/.svelte-kit -/package -.env -.env.* -!.env.example -vite.config.js.timestamp-* -vite.config.ts.timestamp-* diff --git a/packages/node-registry/.npmrc b/packages/node-registry/.npmrc deleted file mode 100644 index b6f27f1..0000000 --- a/packages/node-registry/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/packages/node-registry/.prettierignore b/packages/node-registry/.prettierignore deleted file mode 100644 index cc41cea..0000000 --- a/packages/node-registry/.prettierignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock diff --git a/packages/node-registry/.prettierrc b/packages/node-registry/.prettierrc deleted file mode 100644 index 9573023..0000000 --- a/packages/node-registry/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "useTabs": true, - "singleQuote": true, - "trailingComma": "none", - "printWidth": 100, - "plugins": ["prettier-plugin-svelte"], - "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] -} diff --git a/packages/node-registry/README.md b/packages/node-registry/README.md deleted file mode 100644 index 5ce6766..0000000 --- a/packages/node-registry/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# create-svelte - -Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte). - -## Creating a project - -If you're seeing this, you've probably already done this step. Congrats! - -```bash -# create a new project in the current directory -npm create svelte@latest - -# create a new project in my-app -npm create svelte@latest my-app -``` - -## Developing - -Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: - -```bash -npm run dev - -# or start the server and open the app in a new browser tab -npm run dev -- --open -``` - -## Building - -To create a production version of your app: - -```bash -npm run build -``` - -You can preview the production build with `npm run preview`. - -> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. diff --git a/packages/node-registry/package.json b/packages/node-registry/package.json deleted file mode 100644 index 3d97ee4..0000000 --- a/packages/node-registry/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "node-registry", - "version": "0.0.1", - "private": true, - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "test": "vitest", - "lint": "prettier --check . && eslint .", - "format": "prettier --write ." - }, - "devDependencies": { - "@sveltejs/adapter-auto": "^3.2.0", - "@sveltejs/kit": "^2.5.6", - "@sveltejs/vite-plugin-svelte": "^3.1.0", - "@types/eslint": "^8.56.9", - "@typescript-eslint/eslint-plugin": "^7.7.0", - "@typescript-eslint/parser": "^7.7.0", - "eslint": "^9.0.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-svelte": "^2.37.0", - "prettier": "^3.2.5", - "prettier-plugin-svelte": "^3.2.3", - "svelte": "^4.2.15", - "svelte-check": "^3.6.9", - "tslib": "^2.6.2", - "typescript": "^5.4.5", - "vite": "^5.2.9", - "vite-plugin-wasm": "^3.3.0", - "vitest": "^1.5.0" - }, - "type": "module", - "dependencies": { - "@nodes/utils": "link:../utils", - "utils": "link:../utils" - } -} diff --git a/packages/node-registry/src/app.d.ts b/packages/node-registry/src/app.d.ts deleted file mode 100644 index 743f07b..0000000 --- a/packages/node-registry/src/app.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -// See https://kit.svelte.dev/docs/types#app -// for information about these interfaces -declare global { - namespace App { - // interface Error {} - // interface Locals {} - // interface PageData {} - // interface PageState {} - // interface Platform {} - } -} - -export {}; diff --git a/packages/node-registry/src/app.html b/packages/node-registry/src/app.html deleted file mode 100644 index 77a5ff5..0000000 --- a/packages/node-registry/src/app.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- - diff --git a/packages/node-registry/src/lib/index.ts b/packages/node-registry/src/lib/index.ts deleted file mode 100644 index 856f2b6..0000000 --- a/packages/node-registry/src/lib/index.ts +++ /dev/null @@ -1 +0,0 @@ -// place files you want to import through the `$lib` alias in this folder. diff --git a/packages/node-registry/src/lib/registry.ts b/packages/node-registry/src/lib/registry.ts deleted file mode 100644 index 5dadd66..0000000 --- a/packages/node-registry/src/lib/registry.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { createWasmWrapper } from "@nodes/utils" - -export async function getNodeWasm(id: `${string}/${string}/${string}`) { - - const wasmResponse = await fetch(`/n/${id}/wasm`); - - if (!wasmResponse.ok) { - throw new Error(`Failed to load node ${id}`); - } - - const wrapper = createWasmWrapper(); - const module = new WebAssembly.Module(await wasmResponse.arrayBuffer()); - const instance = new WebAssembly.Instance(module, { ["./index_bg.js"]: wrapper }); - wrapper.setInstance(instance) - - return wrapper; -} - - -export async function getNode(id: `${string}/${string}/${string}`) { - - const wrapper = await getNodeWasm(id); - - const { inputs, outputs } = wrapper?.get_definition?.(); - try { - return { id, inputs, outputs } - } catch (e) { - console.log("Failed to parse input types for node", { id }); - } - - -} diff --git a/packages/node-registry/src/routes/+page.svelte b/packages/node-registry/src/routes/+page.svelte deleted file mode 100644 index 5982b0a..0000000 --- a/packages/node-registry/src/routes/+page.svelte +++ /dev/null @@ -1,2 +0,0 @@ -

Welcome to SvelteKit

-

Visit kit.svelte.dev to read the documentation

diff --git a/packages/node-registry/src/routes/n/[user]/[collection]/[node]/+server.ts b/packages/node-registry/src/routes/n/[user]/[collection]/[node]/+server.ts deleted file mode 100644 index 277846b..0000000 --- a/packages/node-registry/src/routes/n/[user]/[collection]/[node]/+server.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { json } from "@sveltejs/kit"; -import type { RequestHandler } from "./$types"; -import { getNode } from "$lib/registry"; - -export const GET: RequestHandler = async function GET({ fetch, params }) { - globalThis.fetch = fetch; - - const nodeId = `${params.user}/${params.collection}/${params.node}` as const; - - try { - const node = await getNode(nodeId); - return json(node); - } catch (err) { - console.log(err) - return new Response("Not found", { status: 404 }); - } -} diff --git a/packages/node-registry/src/routes/n/[user]/[collection]/[node]/test/+page.svelte b/packages/node-registry/src/routes/n/[user]/[collection]/[node]/test/+page.svelte deleted file mode 100644 index f4741ad..0000000 --- a/packages/node-registry/src/routes/n/[user]/[collection]/[node]/test/+page.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - -

{data.params.user}/{data.params.collection}/{data.params.node}

- -

Node Definition

-{#if !node} -

Loading Node

-{:else} -
{JSON.stringify(node, null, 2)}
-{/if} diff --git a/packages/node-registry/src/routes/n/[user]/[collection]/[node]/test/+page.ts b/packages/node-registry/src/routes/n/[user]/[collection]/[node]/test/+page.ts deleted file mode 100644 index 3146b1d..0000000 --- a/packages/node-registry/src/routes/n/[user]/[collection]/[node]/test/+page.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { PageLoad } from "./$types"; - -export const load: PageLoad = ({ params }) => { - return { - params - } -}; diff --git a/packages/node-registry/src/routes/n/[user]/[collection]/[node]/wasm/+server.ts b/packages/node-registry/src/routes/n/[user]/[collection]/[node]/wasm/+server.ts deleted file mode 100644 index 23dc119..0000000 --- a/packages/node-registry/src/routes/n/[user]/[collection]/[node]/wasm/+server.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { RequestHandler } from "./$types"; -import fs from "fs/promises"; -import path from "path"; - -export const GET: RequestHandler = async function GET({ fetch, params }) { - - const filePath = path.resolve(`../../nodes/${params.user}/${params.collection}/${params.node}/pkg/index_bg.wasm`); - - try { - await fs.access(filePath); - } catch (e) { - return new Response("Not found", { status: 404 }); - } - - const file = await fs.readFile(filePath); - - const bytes = new Uint8Array(file); - - return new Response(bytes, { status: 200, headers: { "Content-Type": "application/wasm" } }); -} diff --git a/packages/node-registry/static/favicon.ico b/packages/node-registry/static/favicon.ico deleted file mode 100644 index 3a7e15064e725de9de488b66401c853bd2f6c5c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5430 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 DV2~;2 diff --git a/packages/node-registry/static/favicon.png b/packages/node-registry/static/favicon.png deleted file mode 100644 index 825b9e65af7c104cfb07089bb28659393b4f2097..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH unknown; + execute?: (args: Int32Array) => Int32Array; } export type Socket = { @@ -44,7 +44,6 @@ export type Socket = { position: [number, number]; }; - export interface NodeRegistry { /** * The status of the node registry