Skip to content
Runtime
Framework

QueryWeave

Type-safe URL state,
woven together.

Define your query model once. Decode, validate, encode, synchronize, and reuse it across browsers, servers, Node.js, and framework adapters.

pnpm add @queryweave/corev0.1.0-alpha.1 is the current source version

Query lifecycleOne model keeps every boundary in step.
  1. Raw query?search=vue&page=2
  2. Decode into
    Typed state{ search: "vue", page: 2 }
  3. Encode into
    Canonical querysearch=vue&page=2
Type in the product search. The URL, the decoded state, and the canonical query below are produced by @queryweave/core and the memory adapter from @queryweave/testing — not by a script written for this page.

History1 / 1

Products

6 matching

  • Edge runtime handbookactive$59
  • Node.js request toolkitactive$39
  • Nuxt deployment guidearchived$19
  • 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
/products

    Model your URL state

    Define the query parameters your page accepts. Each one describes how to decode and encode its value, so you never maintain a separate parser and serializer.

    import { defineQueryModel, param } from "@queryweave/core";
    const products = defineQueryModel({
    search: param.text().optional(),
    page: param.integer({ min: 1 }).default(1),
    sort: param.choice(["name", "created_at", "price"]).default("created_at"),
    });

    Decode into real types

    Call decode() with a query string and you get typed values back. page is a number here, not the string "2". An invalid value recovers to its default and is reported as an issue — it never throws and never disappears silently.

    const result = products.decode("?search=vue&page=2");
    if (result.ok) {
    result.value.page; // 2, typed as number
    } else {
    result.partial; // the keys that did decode
    result.issues; // why the rest did not
    }

    Connect an adapter

    A runtime wires your model to a specific environment. The adapter handles navigation and reports URL changes. Validation stays in the model, not the adapter.

    import { createBrowserAdapter } from "@queryweave/browser";
    import { createQueryRuntime } from "@queryweave/core";
    const runtime = createQueryRuntime({
    model: products,
    adapter: createBrowserAdapter(),
    });
    await runtime.update({ search: "vue" });
    await runtime.update({ page: 2 }, { navigation: "replace" });

    Reuse it everywhere

    Use the same model on the server, in the browser, and in Vue. The model has no framework dependencies, so you define it once and import it wherever the query appears.

    // A request, on any web-standard runtime.
    import { readRequestQuery } from "@queryweave/server";
    const decoded = readRequestQuery(request, products);
    // The same model, bound to Vue reactivity.
    import { useQueryModel } from "@queryweave/vue";
    const filters = useQueryModel(products);

    The model defines parameters, defaults, validation, and canonical encoding. Adapters handle where the query lives and how navigation works. You pick the adapter; the model stays the same.

    QueryWeave package dependency map. Core is the shared foundation. Node builds on the server package. Nuxt builds on the Vue and Vue Router packages.

    1. Nuxt integration — @queryweave/nuxt (Combines Vue bindings with a router adapter for each app)
    2. Node request bridge — @queryweave/node (Turns a Node.js request into a URL and reuses server helpers)
    3. Vue bindings — @queryweave/vue (Makes runtime state reactive and exposes named updates)
    4. Vue Router adapter — @queryweave/vue-router (Reads and changes the query through the router)
    5. Web server helpers — @queryweave/server (Reads a Request or URL and decodes it with a model)
    6. Browser adapter — @queryweave/browser (Reads and changes the URL with the History API)
    7. Memory adapter — @queryweave/testing (Simulates query navigation in tests)
    8. Validation bridge — @queryweave/standard-schema (Connects Standard Schema validators without choosing a vendor)
    9. Core engine — @queryweave/core (Defines query rules and owns decoding, encoding, and state updates)

    Node request bridge → Web server helpers. Nuxt integration → Vue bindings. Nuxt integration → Vue Router adapter.

    The core is the shared foundation for every package. The arrows show the extra package relationships: Node reuses the server helpers, while Nuxt combines the Vue bindings and Vue Router adapter.

    One framework-independent foundation, eight focused integrations. Choose a package to trace the thread it adds.

    @queryweave/core

    Owns the domain vocabulary: parameters, codecs, models, decode results, issues, and the runtime.

    v0.1.0-alpha.1Any ECMAScript runtimeShared foundationOpen package guide

    QueryWeave 0.1.0-alpha.1 is experimental and pre-1.0. The public API may change between minor versions, every breaking change is recorded in an architecture decision record, and the packages are not on npm yet. See the roadmap for what is deliberately absent.