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

@queryjs/client

v0.2.1

Published

Type-safe URL query builder for queryjs

Readme

@queryjs/client

A lightweight, zero-dependency, type-safe URL query builder for full-stack TypeScript applications. Seamlessly construct beautiful, secure URLs on the frontend that map instantly to your @queryjs/core (Prisma, Drizzle, TypeORM) backend backend parser.

npm version License Bundle Size


Why @queryjs/client?

  • Type-Safe Autocomplete: Pass any vanilla TypeScript interface to get instant IDE autocompletion for fields, strict type-checking on values, and valid operators.
  • No More Loose Strings: Replaces error-prone string literals ('gt', '_contains') with a powerful functional operator helper (op.greaterThanOrEqual()).
  • Zero Boilerplate: Built specifically to match the wire-format required by @queryjs/core adapters.
  • Dual ESM/CJS Support: Works out of the box in Next.js, Vite, Remix, Nuxt, Node.js, and mobile applications.

Installation

npm install @queryjs/client
# or
yarn add @queryjs/client
# or
pnpm add @queryjs/client

Quick Start

1. The Zero-Config / Implicit Mode

Get moving in under 10 seconds. Use it as a clean, fluent string builder without any complex types.

import { createQuery, op } from '@queryjs/client';

const urlParams = createQuery()
  .filter('category', 'electronics') // Defaults to implicit equals
  .filter('price', op.greaterThanOrEqual(50))
  .filter('tags', op.in(['premium', 'sale']))
  .sort('createdAt', 'desc')
  .paginate({ page: 1, limit: 12 })
  .toString();

// Emits clean wire format:
// "filter[category]=electronics&filter[price][gte]=50&filter[tags][in][]=premium&filter[tags][in][]=sale&sort=-createdAt&page=1&limit=12"

const response = await fetch(`/api/products?${urlParams}`);

2. The High-Fidelity Type-Safe Mode (Recommended)

Pass your frontend data contract/interface directly to the builder. This prevents spelling mistakes on field keys, type mismatches on values, and invalid operator chains.

import { createQuery, op } from '@queryjs/client';

// Simple model contract (No backend dependencies leaked to the client)
interface Product {
  id: string;
  title: string;
  price: number;
  category: 'electronics' | 'clothing';
  isActive: boolean;
  createdAt: string;
}

const urlParams = createQuery<Product>()
  .filter('category', 'electronics')            // Autocompletes keys & values
  .filter('price', op.greaterThanOrEqual(50))    // TypeScript errors if you pass a string like 'fifty'
  .filter('title', op.contains('laptop'))        // String specific helper
  .search('MacBook', 'prefix')                   // Strict search modifier completion
  .sort('createdAt', 'desc')                     // Validates 'createdAt', blocks arbitrary columns
  .paginate({ page: 2, limit: 25 })
  .toString();

3. The Backend Counterpart

When your frontend sends the URL generated by createQuery(), your backend securely parses, validates, and maps it directly to your ORM using @queryjs/core and its adapters.

import { defineQuery, q } from '@queryjs/core';
import { prismaQueryAdapter } from '@queryjs/prisma';
import express from 'express';

const app = express();
app.set('query parser', 'extended'); // Required for qs nested object parsing

// 1. Define the backend validation schema (mirroring the frontend interface)
const productQuery = defineQuery({
  fields: {
    category: q.enum(['electronics', 'clothing']),
    price: q.number().min(0).sortable(),
    title: q.string().searchable().sortable(),
    createdAt: q.date().sortable()
  },
  limits: { maxLimit: 100 }
});

app.get('/api/products', async (req, res) => {
  // 2. Parse and validate the incoming URL query string
  const validQuery = productQuery.parse(req.query);
  
  // 3. Map it instantly to your ORM (Prisma in this example)
  const { where, orderBy, skip, take } = prismaQueryAdapter.map(validQuery);
  
  const data = await prisma.product.findMany({ where, orderBy, skip, take });
  res.json({ data });
});

API Reference

.filter(fieldName, value | op.helper)

Adds a filter payload constraint to the URL string. If an op helper is omitted, it implicitly generates an equivalence (eq) condition.

The op (Operator) Helpers

Say goodbye to magic strings. Import op to access predictable, typesafe methods:

| Method | Generated Wire Format Key | Description | | :--- | :--- | :--- | | op.equals(value) | [eq] (or implicit) | Exact match | | op.notEquals(value) | [neq] | Not equal to | | op.greaterThan(value) | [gt] | Greater than | | op.greaterThanOrEqual(value) | [gte] | Greater than or equal to | | op.lessThan(value) | [lt] | Less than | | op.lessThanOrEqual(value) | [lte] | Less than or equal to | | op.contains(string) | [contains] | Substring wildcard match | | op.startsWith(string) | [startsWith] | Match beginning of text | | op.endsWith(string) | [endsWith] | Match end of text | | op.isNull() | [isNull]=true | Is null checking | | op.isNotNull() | [isNotNull]=true | Is not null checking | | op.in([...values]) | [in][]=value | Array collection inclusion | | op.notIn([...values]) | [notIn][]=value | Array collection exclusion |

.search(term, modifier?)

Applies a global query string search payload. Optional modifiers include 'exact' and 'prefix'.

.sort(fieldName, direction?)

Applies ordering logic. The directional parameter expects strictly either 'asc' or 'desc' (defaults to 'asc'). Descending parameters are automatically prepended with a - token to match standard backend configurations.

.paginate({ page?, limit? })

Appends pagination offset variables. Expects pure numbers.


Ecosystem Integration

@queryjs/client pairs natively with any application running backend configurations backed by:

  • @queryjs/core
  • @queryjs/prisma
  • @queryjs/drizzle
  • @queryjs/typeorm

License

MIT © johngech