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

@navitech/adapter-bun

v0.2.0

Published

SvelteKit adapter for Bun: one self-contained build/index.js, a Redis ISR cache for pages and remote queries, optional trace spans.

Readme

@navitech/adapter-bun

SvelteKit adapter for Bun. vite build produces one self-contained build/index.js (run it with bun build/index.js), with:

  • static assets and prerendered pages served by the same process, precompressed;
  • a Redis ISR cache for pages and for remote queries, stale-while-revalidate, keyed by build so a deploy never serves the previous build's HTML;
  • optional gates: canonical host, https, Origin-less POST endpoints;
  • a trace span per cache hit when the app uses @navitech/otel — and nothing when it does not.

It replaces the adapter/ directory that was copied from app to app (the ISR adapter, svelte-isr-adapter); it grew out of Mazodor's copy, the most evolved one.

Use

bun add -d @navitech/adapter-bun
// svelte.config.js
import adapter from '@navitech/adapter-bun';

export default {
	kit: { adapter: adapter() }
};
CMD ["bun", "build/index.js"]

The build bundles the adapter's runtime, so the production image needs nothing from this package. The app's own dependencies stay external, as before: install them in the runtime stage.

Options

| option | default | | | --- | --- | --- | | out | build | output directory | | precompress | true | brotli/gzip assets at build time, HTML 200s at runtime | | envPrefix | '' | prefix for the variables below | | serveAssets | true | serve client/ and prerendered/ from this process | | isr | true | the Redis cache; off anyway without REDIS_URL | | cache | src/cache.server.ts | the cache policy module, if it exists | | canonical | false | 308 every host but ORIGIN's to ORIGIN | | forceHttps | false | 308 x-forwarded-proto: http to https | | sessionCookies | auth-session, auth_session, app_session | a request carrying one never touches the cache | | trustedPostPaths | [] | POST paths given ORIGIN as their Origin | | tracing | true | a span per cache hit, if the app has @opentelemetry/api | | bundleDependencies | false | bundle the app's dependencies too; native ones stay external, listed in build/package.json | | external | [] | with bundleDependencies: packages to keep external anyway |

Runtime variables: PORT (3000), HOST (0.0.0.0), SOCKET_PATH, ORIGIN, ADDRESS_HEADER (x-real-ip), XFF_DEPTH (1), BODY_SIZE_LIMIT (10M), IDLE_TIMEOUT (10), REDIS_URL or VALKEY_URL. NODE_ENV=debug logs every cache decision.

Set ORIGIN in production. The adapter rebuilds each request's URL from it; without it, absolute URLs (mails, canonical tags, payment return URLs) come from whatever host the proxy passed through.

Bundled dependencies

With bundleDependencies: true, build/ no longer needs the project's node_modules: every dependency is bundled, except packages with native code (a .node addon, a binding.gyp, prebuilt binaries per platform like sharp, libsql, @node-rs/argon2). Those stay imports, and build/package.json lists them at the versions that were installed. On the platform that will run it:

cd build && bun install --production

For NavitechWebsite that is 3 native packages instead of 261 MB of node_modules. A package that reads its own files at runtime (next to its __dirname) cannot be bundled either; the detection does not see that, name it in external.

The cache

A page is cached when its render emits x-isr-expiration: <seconds> (the TTL) and the visitor is anonymous. What else is required depends on src/cache.server.ts:

import { defineCache } from '@navitech/adapter-bun/cache';

const LANG = '(?:/(?:en|ro))?';

export default defineCache({
	pages: [
		{ match: '/sitemap.xml', expiration: 3600 },
		{
			match: new RegExp(`^${LANG}/products/?$`),
			route: '/[[lang=lang]]/products', // names the trace span of a hit
			expiration: 300,
			bypass: ['q'], // ?q= disables the cache for that request
			query: { page: /^\d{1,3}$/ } // the only param in the key; ?page=99999 renders fresh
		}
	],
	remote: {
		getProducts: { expiration: 300, bypass: (field) => Boolean(field('search')) }
	}
});
  • With pages (recommended), that list is the one gate: a pathname no rule matches is never read from Redis nor written to it. Undeclared query params (utm_*, fbclid) are dropped from the key.
  • Without pages (no module, or no pages key): header mode, the old adapter's behaviour. Every anonymous GET is looked up, keyed by pathname and full query string.
  • remote caches remote query GETs (/_app/remote/<hash>/<name>) by export name. Only results: errors, null and redirects are never stored. Only for queries whose result is the same for every anonymous visitor.

The module is bundled on its own, outside Vite: no $lib, no $env.

Keys are isr:<build id>:<pathname>[?query] and isr:<build id>:remote:<hash>/<name>:<payload>, so invalidation can match isr:*:/products*. Entries are refreshed in the background before they expire. A Redis outage degrades to "no cache": every call has a deadline, and after three failures in a row the cache is skipped for 10 s.

Tracing

With or without, by what the app installs:

  • Without: nothing to do. @opentelemetry/api is not a dependency of this package; without it in the app, tracing does nothing.
  • With (Tracely): install @navitech/otel and @opentelemetry/api, add src/instrumentation.server.ts with import '@navitech/otel/register';, and turn on kit.experimental.tracing.server and kit.experimental.instrumentation.server. The adapter makes Kit's facade load the instrumentation before the server (Tracely/docs/integrating.md).

A cache hit never reaches Kit, so the adapter gives it an entry span of its own, named after the rule's route (GET /[[lang=lang]]/products, GET remote:getProducts) — the same operation as a render, told apart by isr.cache (hit / stale). Only hits: on Bun the collector already makes Kit's root span a render's entry. tracing: false turns these off and leaves Kit's own spans alone.

Moving an app from the copied adapter/

  1. bun add -d @navitech/adapter-bun; delete adapter/; drop rolldown, totalist and mrmime if nothing else uses them.
  2. svelte.config.js: import adapter from '@navitech/adapter-bun'. Keep precompress and isr; Mazodor-style copies add canonical: true, forceHttps: true and their trustedPostPaths.
  3. registerIsrConfig(...) / registerRemoteCacheConfig(...) calls from adapter/files/index.ts become pages / remote in src/cache.server.ts. None: skip.
  4. The Dockerfile's CMD ["bun", "build/index.js"] stays; build/index.js is now real JS.

Develop

bun install
bun run check   # tsc over src/ (Node, build time) and runtime/ (Bun)
bun run test    # unit tests, then builds test/fixture three ways and runs it

The end-to-end tests need redis-server on PATH for the cache cases (skipped otherwise).

Layout: src/index.ts is the adapter (runs in Vite at build time); runtime/ is the server, shipped as TypeScript and bundled into each app's build with Kit's output — the adapter:* imports are resolved there. runtime/isr.ts holds the cache's decisions as pure functions.

Publishing

Bump version, then npm publish (prepublishOnly runs check and tests). Public, like @navitech/otel.