@selvajs/solve
v1.0.0-beta.9
Published
One owner for the Selva solve flow — input change to solve result, on both sides of the wire, with no transport and no UI
Maintainers
Readme
@selvajs/solve
One owner for the solve flow — from an input change to a solve result, on both sides of the wire, with no transport and no UI.
Before this package the solve flow was scattered across four packages and owned by none of them, so both apps hand-wrote a solve coordinator — and one of them ended up serving results from the wrong definition out of its cache.
Layout
shared/ the vocabulary both halves speak — SolveResult, SolveFn, SolveInput, input keying
client/ form state machine, auto/manual decision, throttle, result memo, driver seam
server/ solve pipeline (tree build → solve → serialize → envelope), caches, single-flightclient/ and server/ both depend on shared/, and never on each other. See
src/server/README.md for how that's
enforced.
See src/client/README.md for the session, the driver seam, and how to
write a transport; src/server/README.md for the pipeline and the cache
tiers.
What it must never know
- No UI framework. No Svelte, no runes, no DOM.
client/is a state machine, not a component. - No renderer. No
three.SolveResult<TMesh>never inspects a mesh — the app that parses a response intoTHREE.Object3D[]is the only place that knows the concrete type. This is what lets a headless CLI solve without dragging in a parse layer. Seesrc/client/README.mdfor how the result memo handles mesh ownership without knowing what a mesh is. - No authorization, orgs, projects, or share links. App policy.
- No HTTP.
client/stops at aSolveFn;server/stops at aSolveOutcome. Mapping either to a status code is the app's job.
No root barrel — on purpose
@selvajs/solve exports ./shared, ./client and ./server. There is deliberately no . export:
a root barrel re-exporting both halves would let a browser bundle reach server code — and server
credentials — through one innocent-looking import, defeating every other guard. Adding one is a
boundary change, not a convenience.
import type { SolveResult } from '@selvajs/solve/shared';import { createSolveSession, createRequestResponseDriver } from '@selvajs/solve/client';
import { runSolvePipeline } from '@selvajs/solve/server';@selvajs/server/compute keeps only the HTTP request policy it owns (limits, rate limiting, the
SSRF guard, remote-definition fetch) and does not re-export any of this — the two packages are
independent.
