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

@tinloof/astro-prefetch

v0.1.1

Published

Next.js-style prefetching for Astro's ClientRouter: in-memory cache, cursor-trajectory (proximity) prediction, and instant navigations.

Readme

@tinloof/astro-prefetch

Next.js-style prefetching for Astro's <ClientRouter />: an in-memory page cache the router swaps from, with a cursor-trajectory ("proximity") predictor that starts the request before hover even fires.

Live playground — debug overlay on, every option tunable from the control panel.

Astro's built-in prefetch only emits browser hints (<link rel="prefetch">, speculation rules) whose responses JavaScript can't read back — navigation still refetches. This integration owns the whole pipeline instead:

  • Cache — entry state machine (pending → fulfilled | rejected), per-entry TTL, byte-budget LRU.
  • Scheduler — Intent > Default > Background priority queue, in-flight dedup, concurrency caps (4/12, Next.js's values).
  • Triggers — Astro's tap / hover / viewport strategies (data-astro-prefetch compatible; load is not supported) plus proximity: project the cursor's velocity lookaheadMs ahead and prefetch the link it's heading toward. Keyboard focus prefetches for every strategy (keyboard navigation has no trajectory — focus is the intent signal). Links rendered after page load (islands, mega menus) are picked up via mutation observation.
  • Navigationastro:before-preparation loader override: fresh hit swaps with zero network; a click during an in-flight prefetch awaits that same request (never two); misses populate the cache so back/forward becomes a hit. Every failure path falls back to Astro's default loader.

Install

pnpm add @tinloof/astro-prefetch
// astro.config.mjs
import { defineConfig } from "astro/config";
import prefetch from "@tinloof/astro-prefetch";

export default defineConfig({
  integrations: [prefetch()],
});

Requires <ClientRouter /> from astro:transitions on every page. The built-in prefetch config is disabled automatically. Inert in astro dev (the dev loader has dev-only duties we don't replicate) — test with astro build && astro preview.

Options

prefetch({
  defaultStrategy: "proximity", // tap | hover | viewport | proximity
  prefetchAll: true,            // links without data-astro-prefetch participate
  proximity: {                  // or false to disable the predictor
    lookaheadMs: 150,           // how far ahead to project the cursor — the "how early" dial
    radiusPx: 64,               // extra hit area around each link's rect
    minSpeedPxS: 80,            // slower = drift; hover handles it
    maxSpeedPxS: 2500,          // faster = flick; overshoots
    sampleWindowMs: 80,         // velocity estimation window
    tickMs: 50,                 // evaluation throttle
  },
  staleTimeMs: 30_000,          // cache TTL; x-prefetch-stale-time response header (seconds) overrides
  maxCacheBytes: 50 * 1024 * 1024, // LRU budget
  debug: false,                 // true | { badge, overlay } — loaded as a separate chunk
});

Per-link data-astro-prefetch="tap|hover|viewport|proximity|false" always overrides defaultStrategy. Astro's load value is not supported — links carrying it are not prefetched.

debug

debug: true enables:

  • a badge (bottom-right) classifying each navigation: CACHE HIT / AWAITED PREFETCH / CACHE MISS / DIRECT, with elapsed ms
  • a proximity overlay: each candidate link's hit area, the cursor's velocity ray to the projected point, live px/s, and a green flash on the link the predictor prefetches

Programmatic API

import {
  prefetch,
  invalidate,
  getEntry,
  configure,
  PROXIMITY_HIT_EVENT,
} from "@tinloof/astro-prefetch/client";

prefetch("/checkout", { priority: "intent" });
invalidate("/cart"); // after a mutation; no argument clears everything
getEntry("/checkout"); // inspect a URL's cache entry

// Live-reconfigure any option after init — control panels, A/B tests,
// runtime tuning. Only the keys present are applied.
configure({
  proximity: { lookaheadMs: 300 }, // merge-tune the predictor
  debug: { badge: true, overlay: false }, // toggle visuals (with teardown)
});
configure({ proximity: false }); // pause the predictor

// Fired on document for every link the predictor decides to prefetch;
// detail carries { anchor, href }.
document.addEventListener(PROXIMITY_HIT_EVENT, (e) => console.log(e.detail));

The playground app (apps/playground) is a working reference: its control panel drives everything through configure().

Server notes

  • Prefetch requests carry x-astro-prefetch: 1 — identify them for CDN rules or cheaper rendering. If the server varies on it, send Vary: x-astro-prefetch.
  • Respond with x-prefetch-stale-time: <seconds> to control per-page TTL (floored at 30s).
  • Responses with Cache-Control: no-store or Vary: Cookie are never cached.
  • Personalized HTML: call invalidate() after login/cart mutations, or keep staleTimeMs short.

Caveats

  • The navigation consume path replicates internal behavior of Astro's transitions/router.js defaultLoader (redirect replay, stylesheet preload) — verified byte-equivalent on astro 5.18 and 6.4. Re-check on major Astro upgrades; all failure paths fall back to the default loader.
  • A view-transition swap is atomic: streamed pages are buffered before swapping (the default loader does the same). For slow streaming pages, move the slow data into server:defer islands — the cached shell swaps instantly and islands stream in fresh after.