Server
Adapter
Web-standard `Request` and `URL` helpers for request-scoped decoding.
- Package
- @queryweave/server
- Runtime
- Any web-standard server, edge, or worker runtime
- Depends on
- @queryweave/core
- Framework required
- No
This package decodes the query of a Request or a URL with a model, builds a canonical query
string or a complete URL from typed state, and gives you a read-only QuerySource scoped to one
request.
It cannot navigate. A request is read once and then ends, so there is no history to push to. That is
why the package returns a QuerySource instead of a QueryAdapter: the navigation methods are
missing from the type, so nothing can call them and fail at runtime.
Request-scoped source — reads once, never navigates
Request-scoped source — reads once, never navigates
- Request (incoming)
- QuerySource (read-only)
- QueryModel.decode() (typed result)
Request → QuerySource. QuerySource → QueryModel.decode().
Install
Section titled “Install”pnpm add @queryweave/core @queryweave/serverNo Node built-in is used anywhere in the package, so it runs unchanged on Node.js, Deno, Bun,
Cloudflare Workers, and any other runtime with Request and URL. Node.js is the runtime the
repository tests on; the others are supported by construction, not by a fixture — see
Support and stability.
Example
Section titled “Example”import { readRequestQuery } from "@queryweave/server";
export async function handler(request: Request): Promise<Response> { const result = readRequestQuery(request, products); const values = result.ok ? result.value : { ...products.defaults(), ...result.partial };
return Response.json({ products: await search(values), issues: result.issues, });}The merge on the second line is the standard pattern: render something useful, and keep the issues for diagnostics.
Reading
Section titled “Reading”readUrlQuery(url, model); // string | URLreadRequestQuery(request, model); // Request
await readUrlQueryAsync(url, model); // when validation is asynchronousawait readRequestQueryAsync(request, model);Only the query is ever read, and it is read from the string itself — the part between the first ?
and any # — so a relative path, an absolute URL, or a request line with an unusual host all work
and none of them throws. relativeUrlBase (http://queryweave.invalid) is the origin
createQueryUrl uses for a base that is not absolute, exported so tests can assert against it.
const result = readUrlQuery("/products?search=vue&page=2", products);
result.ok; // trueif (result.ok) result.value; // { search: "vue", page: 2, ...defaults }A request-scoped source
Section titled “A request-scoped source”import { createRequestQuerySource } from "@queryweave/server";
const source = createRequestQuerySource(request);
source.read(); // "?page=2"source.request; // the original RequestUse this when a helper wants a QuerySource rather than a decoded result — for example, code that
should work with any read-only environment.
Building links
Section titled “Building links”import { createQueryUrl, encodeQuery } from "@queryweave/server";
encodeQuery(products, { search: "vue", page: 2, sort: "created_at", status: "all" });// "search=vue&page=2"
createQueryUrl("https://example.com/products?utm_source=email", products, values);// https://example.com/products?search=vue&page=2&utm_source=emailencodeQuery returns the canonical query string with no leading ?. createQueryUrl returns a
URL, and it is the one place outside the runtime that preserves unmanaged keys: managed keys are
written first, and everything the model does not declare follows in its original order.
Server mode in the simulator
Section titled “Server mode in the simulator”History—
- Request URL
- decode
- typed result
- canonical URL
A request is read once. There is no history to move through, so navigation is absent.
Type a query, press Enter.
Typed state
{
"page": 1,
"sort": "created_at",
"status": "all"
}Canonical URL
Valid/productsEdge cases
Section titled “Edge cases”- An absolute URL is used as given. A string that parses as absolute is not re-based by
createQueryUrl; the readers never build a URL at all. - A malformed query does not throw. It decodes with issues, exactly as in the browser.
createQueryUrlmutates nothing. It copies the base URL before writing tosearch.- Repeated unmanaged keys keep their order and multiplicity.