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

@filterbridge/browser

v0.1.0

Published

Browser URL synchronization helpers for FilterBridge filters.

Readme

@filterbridge/browser

Status: experimental — API may change before the first stable release.

Browser URL synchronization helpers for FilterBridge.

Lets you initialize filter state from the current URL and keep the URL updated as filters change — without a framework adapter.


Installation

pnpm add @filterbridge/browser @filterbridge/core

Quick example

import { parseFiltersFromUrl, replaceUrlFilters } from '@filterbridge/browser'
import { useFilterBridge } from '@filterbridge/react'
import { defineFilters, text, select, boolean } from '@filterbridge/core'

const invoiceFilters = defineFilters({
  search: text(),
  status: select(['pending', 'paid', 'failed'] as const),
  archived: boolean(),
})

function InvoicesPage() {
  const bridge = useFilterBridge(invoiceFilters, {
    // Initialize from the current URL on first render
    initialState: parseFiltersFromUrl(invoiceFilters),
    // Write back to the URL on every change
    onChange(state) {
      replaceUrlFilters(invoiceFilters, state)
    },
  })

  return (
    <input
      value={bridge.state.search ?? ''}
      onChange={(e) => bridge.set('search', e.target.value)}
    />
  )
}

Result: /invoices/invoices?search=acme as the user types. Reloading the page restores the search filter.


API

parseFiltersFromUrl(schema, input?)

Parses filter state from a URL or search string.

// Read from window.location.search
parseFiltersFromUrl(filters)

// String
parseFiltersFromUrl(filters, '?search=acme&status=paid')

// URL object
parseFiltersFromUrl(filters, new URL('https://example.com/?search=acme'))

// URLSearchParams
parseFiltersFromUrl(filters, new URLSearchParams('search=acme'))

// location-like
parseFiltersFromUrl(filters, { search: '?search=acme' })

Returns InferFilterState<typeof schema>. Returns {} safely when window is not available.


createFilterUrl(schema, state, options?)

Creates a URL path string from schema and state.

createFilterUrl(filters, { search: 'acme' }, { pathname: '/invoices' })
// "/invoices?search=acme"

// Preserving non-filter params
createFilterUrl(filters, { search: 'acme' }, {
  pathname: '/invoices',
  currentSearch: '?page=2&tab=open',
})
// "/invoices?page=2&tab=open&search=acme"

// Removing old filter params
createFilterUrl(filters, {}, {
  pathname: '/invoices',
  currentSearch: '?page=2&search=old&status=paid',
})
// "/invoices?page=2"

Options:

type CreateFilterUrlOptions = {
  pathname?: string                        // Default: window.location.pathname or "/"
  currentSearch?: string | URLSearchParams // Existing params to preserve
  hash?: string                            // Hash fragment without #
  preserveExistingParams?: boolean         // Default: true
}

replaceUrlFilters(schema, state, options?)

Updates the browser URL via window.history.replaceState. Does not add a history entry.

replaceUrlFilters(filters, { search: 'acme' })

Automatically reads window.location.search to preserve non-filter params. Safe to call outside a browser — no-op when window.history is not available.


pushUrlFilters(schema, state, options?)

Same as replaceUrlFilters, but uses window.history.pushState.

pushUrlFilters(filters, { search: 'acme' })

getFilterParamKeys(schema)

Returns the URL search-param keys produced by the schema.

getFilterParamKeys(defineFilters({
  search: text(),
  issuedAt: dateRange(),
  amount: numberRange(),
}))
// ["search", "issuedAtFrom", "issuedAtTo", "amountMin", "amountMax"]

Preserving non-filter params

When you call replaceUrlFilters, params that are not part of your schema are preserved by default.

Example: URL is /orders?page=2&search=acme. You clear the search filter. Result: /orders?page=2.


SSR safety

All helpers return empty state / no-op safely when window is not available.


Limitations

  • No popstate handler — back/forward navigation does not update React state.
  • No Next.js App Router integration — use @filterbridge/next instead.
  • No React Router integration.
  • No debounce built in.

Related packages