Quick start
Five steps, none of which mention a framework until the last one.
-
Define a query model
Section titled “Define a query model”products.ts import { defineQueryModel, param } from "@queryweave/core";export const products = defineQueryModel({search: param.text().optional(),page: param.integer({ min: 1 }).default(1),sort: param.choice(["name", "created_at", "price"]).default("created_at"),status: param.choice(["all", "active", "archived"]).default("all"),});searchis optional: when its key is absent, the decoded value isundefined. The other three have defaults, so they always decode to a concrete value even when the key is missing from the URL. -
Decode a URL
Section titled “Decode a URL”const result = products.decode("?search=vue&page=2");result.ok; // true for this inputif (result.ok) {result.value;// {// search: "vue", — from the URL// page: 2, — from the URL, typed as number// sort: "created_at", — not in the URL; the default fills it in// status: "all", — same// }}decodereturns complete typed state: every key in the model, with defaults used when a key is missing from the URL. It accepts a query string, an iterable of entries (includingURLSearchParams), or a plain object, and it never throws. -
Handle what did not decode
Section titled “Handle what did not decode”const result = products.decode("?page=abc");result.ok; // true — the invalid page recovered to its defaultif (result.ok) {result.value.page; // 1result.value.sort; // "created_at"}result.issues[0]?.code; // "invalid"result.issues[0]?.key; // "page"An invalid value produces an issue and a recovery.
pagefalls back to its default rather than vanishing, so the page still renders while the problem stays reportable. -
Encode typed state
Section titled “Encode typed state”products.encode({ search: "vue", page: 1, sort: "created_at", status: "all" });// [["search", "vue"]]page,sort, andstatusare omitted because each equals its declared default. Canonical output is the shortest encoding that decodes back to the same state. -
Choose a runtime integration
Section titled “Choose a runtime integration”Everything above works without a browser or framework. A runtime connects the model to a place that stores and navigates the query.
Where are you using QueryWeave?
Browser
History API synchronization with push, replace, and popstate.
Read the Browser guideimport { createBrowserAdapter } from "@queryweave/browser";import { createQueryRuntime } from "@queryweave/core";const runtime = createQueryRuntime({model: products,adapter: createBrowserAdapter(),});await runtime.update({ search: "vue" });Server
Web-standard `Request` and `URL` helpers for request-scoped decoding.
Read the Server guideimport { readRequestQuery } from "@queryweave/server";export function handle(request: Request) {const result = readRequestQuery(request, products);return result.ok ? result.value : { ...products.defaults(), ...result.partial };}Node.js
Node request primitives bridged into the server helpers.
Read the Node.js guideimport { readNodeQuery } from "@queryweave/node";createServer((request, response) => {const result = readNodeQuery(request, products);response.end(JSON.stringify(result.ok ? result.value : result.partial));});Vue
Readonly reactive values and explicit operations, bound to one model.
Read the Vue guideimport { useQueryModel } from "@queryweave/vue";const filters = useQueryModel(products);filters.values.page; // readonly reactive stateawait filters.update({ page: 2 });Vue Router
A router-backed adapter that keeps path and hash intact.
Read the Vue Router guideimport { createVueRouterAdapter } from "@queryweave/vue-router";import { provideQueryAdapter } from "@queryweave/vue";provideQueryAdapter(createVueRouterAdapter(router));Nuxt
A module plus a request-scoped runtime plugin for server rendering.
Read the Nuxt guidenuxt.config.ts export default defineNuxtConfig({modules: ["@queryweave/nuxt"],});
See it run
Section titled “See it run”The simulator below is driven by the model from step 1, createQueryRuntime from
@queryweave/core, and the memory adapter from @queryweave/testing. Switch Navigation between
push and replace and watch the history counter; switch Adapter to Server and the history
controls disappear, because a request has none.
History1 / 1
- history.pushState
- history.replaceState
- popstate
The adapter writes through the History API and re-reads on popstate.
Type a query, press Enter.
Typed state
{
"page": 1,
"sort": "created_at",
"status": "all"
}Canonical URL
Valid/productsWhat you now have
Section titled “What you now have”- One description of the query, usable on both sides of a request.
- Types that follow from the model rather than being written twice.
- Canonical URLs, so equal states produce equal links.
- Issues you can render, rather than exceptions you must catch.
- Query models — composition, defaults, and model-level refinement.
- The query runtime — transitions, subscriptions, and unmanaged keys.
- Adapters — where a query is actually stored.