npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@selvajs/compute

v2.1.0

Published

TypeScript library for Rhino Compute Server - Grasshopper and RhinoCommon

Readme

npm version npm downloads License: MIT TypeScript Node.js GitHub Repository

@selvajs/compute

An intermediate-level TypeScript framework for building web applications with Rhino Compute and Grasshopper.

@selvajs/compute simplifies the process of communicating with Rhino Compute, handling Grasshopper definitions, and visualizing results in the browser with Three.js.

Installation

npm install @selvajs/compute three

(Note: three is a peer dependency if you use the visualization features)

Why this project exists

@selvajs/compute provides a type-safe, production-ready foundation for building with Rhino Compute:

  • Type-safe API — Full TypeScript with structured error codes and rich error context.
  • High-level clientGrasshopperClient for one-off solves, client.createScheduler() for any UI that fires solves frequently.
  • Robust transport — Configurable timeout, caller-supplied AbortSignal, exponential-backoff retries on transient errors, and Retry-After honored on 429.
  • Slider-friendlylatest-wins scheduling aborts stale solves when newer values arrive. Optional response cache makes repeated inputs instant.
  • Ready-to-use visualization — Integrated Three.js setup with initThree() and configurable rendering options.

Whether you're building a simple solver, a slider-driven configurator, or a long-running job submission flow, @selvajs/compute handles the plumbing so you can focus on your Grasshopper definitions.

What this is not: a job queue. For solves longer than a couple of minutes, run this library server-side behind your own queue (BullMQ / SQS / Cloud Tasks) and expose a status endpoint to the browser.

Note: The library currently focuses on the Grasshopper endpoint but is designed to support other Rhino Compute endpoints in future releases.

Quickstart

Every solve in @selvajs/compute goes through a scheduler. The scheduler handles cancellation, retries, loading state, and (optionally) a response cache — things every real app needs and shouldn't have to rebuild.

import { GrasshopperClient, TreeBuilder, GrasshopperResponseProcessor } from '@selvajs/compute';

const client = await GrasshopperClient.create({
	serverUrl: 'http://localhost:6500',
	apiKey: 'your-api-key'
});

// Configure the scheduler for your workload (see "Configuring the scheduler" below).
const scheduler = client.createScheduler({ mode: 'latest-wins', timeoutMs: 30_000 });

// Inspect the definition's inputs once, build a data tree.
const io = await client.getIO('my-definition.gh');
const inputTree = TreeBuilder.fromInputParams(io.inputs);

// Solve. Returns a Promise — call it as often as you like.
const result = await scheduler.solve('my-definition.gh', inputTree);
const { values } = new GrasshopperResponseProcessor(result).getValues();

Wire the scheduler's state into your UI for spinners and disabled buttons:

scheduler.subscribe(() => {
	showSpinner = scheduler.isSolving;
	disableSubmit = scheduler.hasPending;
});

And handle expected cancellations gracefully — when newer values supersede an in-flight solve, or when the user aborts:

scheduler.solve(definition, inputTree).catch((err) => {
	if (/superseded|aborted/i.test(err.message)) return; // expected, not an error
	showError(err);
});

Configuring the scheduler

The scheduler is one API with two knobs that matter — mode and timeoutMs — plus a couple of optional ones. Pick the row that matches what the user is doing in your UI:

| Workload | mode | timeoutMs | retry | Notes | | --------------------------------- | --------------- | ---------------- | ----------------- | ----------------------------------------------------------------------------------------------------- | | Slider scrubs / live previews | 'latest-wins' | 30_000 | default | Aborts in-flight solves when newer values arrive. Add cache: { ttlMs: 60_000 } for instant repeats. | | Submit / long-running jobs | 'queue' | 0 (no timeout) | { attempts: 1 } | Serial queue. Pass a caller signal so users can hit Cancel. Bump proxy idle timeouts (see below). | | Background / batch parallel | 'parallel' | 60_000 | { attempts: 2 } | Fires solves concurrently up to maxConcurrent (default 4). |

You can create multiple schedulers from one client — typically one per UI surface. They share the connection pool but their queues, cancel scopes, and caches are independent:

const previewScheduler = client.createScheduler({ mode: 'latest-wins', timeoutMs: 30_000 });
const submitScheduler = client.createScheduler({
	mode: 'queue',
	timeoutMs: 0,
	retry: { attempts: 1 }
});

Cancellation

Pass a per-call signal to cancel just that solve, or call cancelAll() to cancel everything (e.g. on route change or component unmount):

const ctrl = new AbortController();
scheduler.solve(definition, tree, { signal: ctrl.signal });

// Later:
ctrl.abort(); // cancel just this call
scheduler.cancelAll(); // cancel everything in flight + pending
scheduler.dispose(); // cancel everything and tear down the scheduler

Long jobs behind a proxy

Cloudflare's default idle timeout is 100s; AWS ALB's is 60s; nginx is 60s. If your Compute server is behind any of them, those values must be bumped before you can run long solves through the browser — the library cannot work around proxy timeouts.

For solves longer than ~2 minutes, the safer architecture is to run this library server-side behind your own job queue (BullMQ / SQS / Cloud Tasks) and expose a status endpoint to the browser.

Requirements

Core Requirements

  • Node.js >= 20
  • three >= 0.179.0 (required for visualization features)

Rhino Compute Compatibility

@selvajs/compute works with both standard Rhino Compute and enhanced versions:

Standard Rhino Compute – The official McNeel repository works for basic Grasshopper solving with core features.

Enhanced Setup (Recommended) – Unlock advanced features:

  1. Selva Rhino Plugin – Grasshopper plugin that simplifies building Three.js visualizations and exporting results directly from Grasshopper. Download from Food4Rhino. Detailed documentation will be available when the Selva project is open-sourced.
  2. Custom Compute Server – Our custom branch enables:
    • Input Grouping – Organize inputs with the groupName property
    • Persistent IDs – Uniquely identify inputs across definition changes using Grasshopper object GUIDs

Features requiring the enhanced setup will be clearly marked in the documentation.

Troubleshooting

Network error: Failed to fetch

The browser couldn't reach the server. Check, in order:

  1. Server is runningcurl http://localhost:6500/healthcheck should return a 200.
  2. CORS — if your Compute server is on a different origin than your app, the server must send Access-Control-Allow-Origin. Standard Rhino Compute does not ship with CORS enabled; you'll need to put it behind a proxy that adds the headers, or use the VektorNode custom branch.
  3. Mixed content — an HTTPS app can't fetch from an HTTP server. Either serve Compute over HTTPS or develop locally on HTTP.
  4. API key — you'll see the same error if your apiKey is missing for a server that requires one (the server typically returns 401 with no CORS headers, which the browser surfaces as a network error).

Solves timing out before the server finishes (502 / 504 / aborted)

The bottleneck is almost always a proxy in front of Compute, not the library. Common culprits:

  • Cloudflare — 100s idle timeout on free/pro plans (525s on enterprise).
  • AWS ALB — 60s default; raise via the idle_timeout attribute.
  • nginx — 60s default; set proxy_read_timeout and proxy_send_timeout.

For solves longer than ~2 minutes, prefer running this library server-side and exposing your own job-status endpoint to the browser. Direct browser → Compute is fine for short solves but fragile for long ones.

Definition URL/content is required

You called client.solve('', tree) or passed a Uint8Array of length 0. Validate your input before calling.

401 vs 403

  • 401 UnauthorizedapiKey (RhinoComputeKey header) is missing or invalid. Standard Rhino Compute uses this scheme.
  • 403 Forbidden — your authToken (Bearer) was rejected by an upstream proxy/API gateway. The Compute server itself almost never returns 403.

The error message includes the response body excerpt so you usually get a hint from the server itself.

"Superseded by newer solve" errors flooding my console

That's the scheduler doing its job in latest-wins mode — every aborted slider solve rejects with this message. Filter it out:

scheduler.solve(def, tree).catch((err) => {
	if (/superseded|aborted/i.test(err.message)) return; // expected, not an error
	showError(err);
});

"Failed to load three.js visualization module"

The dynamic import of the visualization layer threw. Make sure three is installed (npm install three) — it's a peer dependency, not a direct one.

Acknowledgement

This library is built on production experience and draws from several official McNeel repositories. Where code has been adapted, it is clearly marked in the relevant files.

Key References:

License

MIT