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

@rakun-kit/bun

v0.1.11

Published

Bun framework adapter for Rakun APIs, manager, filesystem modules, SSR, and static routes.

Readme

@rakun-kit/bun

Bun 1.4 framework adapter for Rakun. It runs Rakun API, manager, web rendering, static routes, dynamic routes, and development reloads from one Bun.serve() process.

Install

bun add @rakun-kit/bun @rakun-kit/core @rakun-kit/manager-react @rakun-kit/react react react-dom

Bun uses its native password implementation, so this adapter does not require the bcrypt package.

Add scripts to the application:

{
  "scripts": {
    "dev": "rakun-bun dev",
    "build": "rakun-bun build",
    "start": "rakun-bun start"
  }
}

Create a typed rakun.config.ts. bootstrap accepts the same RakunBootstrapOptions used by the other Rakun adapters; the remaining fields configure the Bun framework:

import type { RakunBunConfig } from '@rakun-kit/bun'
import { createRakunBootstrap } from './src/rakun/bootstrap'

const bunConfig: RakunBunConfig = {
  bootstrap: createRakunBootstrap,
  modulesDir: './src/modules',
  revalidation: {
    token: process.env.RAKUN_REVALIDATE_TOKEN!,
  },
}

export default bunConfig

The default paths are /api, /manager, /_rakun/rsc, /_rakun/revalidate, and /assets. revalidation configures core to call the same Bun process after Rakun resolves affected content to paths.

Files in public/ at the application root (next to src/) are served from the same URL path, before web page rendering. Production builds copy that directory to dist/public, while development serves it directly from the source folder.

The manager preview is enabled for the same Bun origin by default. Set manager: { preview: false } to disable it, or provide webBaseUrl and tokenParam when the web application is hosted elsewhere or uses a custom preview query parameter. Preview requests with that token are resolved through Rakun's web.previewPage operation.

Production route and gzip caches are bounded by count, bytes, and idle time. The defaults retain at most 128 rendered routes and 32 MiB in each cache, purge entries after five idle minutes, and keep the newest two complete disk generations per static route. Override them when needed:

const bunConfig: RakunBunConfig = {
  cache: {
    routeMaxEntries: 64,
    routeMaxBytes: 16 * 1024 * 1024,
    routeIdleTimeoutMs: 60_000,
    routeMaxGenerations: 2,
    assetMaxBytes: 16 * 1024 * 1024,
    assetIdleTimeoutMs: 60_000,
  },
}

Expired routes are reloaded from disk without regeneration. Use 0 for an idle timeout to disable time-based eviction, or 0 for a byte/entry limit to disable that memory cache.

Filesystem modules

Both forms are discovered without an index registry:

src/modules/Hero.tsx
src/modules/Gallery/index.tsx

The resulting names are Hero and Gallery. Duplicate names fail the build. Modules are server-rendered by default and their code is absent from browser bundles. A top-level 'use client' directive creates a self-contained browser bundle and a hydrated island. Rakun also follows static imports, so a server module is promoted to a client boundary when it imports a client component from another file or Image (and other client exports) from @rakun-kit/react:

'use client'

import { useState } from 'react'

export default function Counter({ initial = 0 }) {
  const [value, setValue] = useState(initial)
  return <button onClick={() => setValue(value + 1)}>{value}</button>
}

An unresolved route uses the framework's empty NotFound fallback and returns HTTP 404. Add src/modules/NotFound.tsx to render an application-specific 404 module; Bun keeps the response status and marker automatically.

Rakun page content stays separate from this code. A content save regenerates only the HTML and path-scoped render payload; source changes rebuild code and hashed assets.

Rendering and navigation

web.staticPaths is the source of truth for build-time routes. Each static path gets HTML plus a flight.rsc render payload. Other paths resolve through web.page at request time. Client navigation requests /_rakun/rsc/*, swaps the rendered tree, and imports only client bundles referenced by the destination page. Web module bundles, navigation, and the manager are built as independent graphs, so a public page never downloads manager code or incidental shared chunks. The manager keeps its own lazy-loaded graph under /assets/manager/; route chunks produced by React.lazy load only after that manager route is visited. Production builds consolidate the manager shell into one initial script, emit one lazy root bundle per built-in manager screen, and retain only genuinely shared supporting chunks. Lucide's runtime registry is also reduced to the menu and module-picker icons declared by the bootstrapped content types instead of emitting the complete icon catalog.

The manager receives a Bun-provided linkComponent; Bun owns manager click routing and prefetches built-in route chunks on hover, focus, or touch.

Internal links prefetch their flight and destination client modules on hover, focus, or touch, so the subsequent navigation can reuse the warmed response. API and manager links keep their normal full-document navigation behavior.

Use the exported Link component for web links when prefetch needs to be disabled for a specific destination:

import { Link } from '@rakun-kit/bun'

<Link href="/about">About</Link>
<Link href="/large-report" prefetch={false}>Large report</Link>

Client modules can read the current URL pathname with usePathname(). The hook returns the server-rendered pathname on first render and updates after Rakun client navigation, including browser back and forward navigation:

'use client'

import { usePathname } from '@rakun-kit/bun'

export default function NavigationStatus() {
  const pathname = usePathname()
  return <span>{pathname}</span>
}

Add src/document.tsx to define the application shell. It is a server component and follows the same children layout shape as a Next.js root layout:

import type { RakunBunDocumentProps } from '@rakun-kit/bun'

import './globals.css'

export default function Document({ children, page }: RakunBunDocumentProps) {
  return (
    <html lang={page.language?.code ?? 'en'}>
      <head>
        <link rel="icon" href="/favicon.svg" />
      </head>
      <body>
        <div className="site">{children}</div>
      </body>
    </html>
  )
}

The framework bundles global CSS imported by the document and injects page SEO, styles, navigation scripts, and the Rakun root inside the rendered document. The file must export a default server component. Configure PostCSS plugins through css.plugins; Rakun runs them for CSS from the application source tree in both development and production. For Tailwind CSS v4:

bun add -d tailwindcss @tailwindcss/postcss
import tailwindcss from '@tailwindcss/postcss'

const bunConfig: RakunBunConfig = {
  css: {
    plugins: [tailwindcss()],
  },
}

Then import @import 'tailwindcss'; from the stylesheet directly. No generated CSS file or separate watcher is required.

Path invalidation

The public primitive is invalidatePath(path). Static regeneration renders a new generation separately, writes complete HTML and render payload files, then swaps the in-memory route pointer. Failed rendering leaves the previous version available.

const app = createRakunBun(config)
await app.invalidatePath('/about')

The authenticated HTTP endpoint accepts the existing core revalidation shape:

POST /_rakun/revalidate
Authorization: Bearer <token>
Content-Type: application/json

{"path":"/about"}

invalidateTag is intentionally not implemented. Rakun remains responsible for content relationships and calculating affected paths.

Static HTML and flight responses require browser revalidation, so a regenerated path cannot remain hidden behind a stale browser cache. Requests carrying the manager preview token bypass the static route cache entirely and are served with Cache-Control: no-store.

Development and production

rakun-bun dev watches src and an external module directory when configured. It rebuilds the document and server graph for server-only changes, rebuilds only the affected client entries when a client module changes, invalidates static routes for lazy regeneration, and replaces the rendered tree over the development WebSocket. A failed rebuild leaves the current application active; a browser-side update failure falls back to a page reload.

The first development build stores the browser, navigation, and manager build metadata and assets in .rakun/cache. Later starts use file metadata as a fast path and verify changed candidates against the stored hashes before reusing the client, navigation, and manager output. The cache is independent from dist, so a production build does not make the next development start cold. Missing cached outputs or a changed dependency cause a normal rebuild. Incremental client rebuilds refresh the persistent cache for the following process. The server graph has its own validated cache and is imported into each new process; changing any of its source inputs rebuilds it. The cache is disposable and .rakun/ should remain ignored by source control.

Development does not load or prerender web.staticPaths. Every web and flight request is rendered dynamically with Cache-Control: no-store, even when core marks the page as static. Route-cache persistence and static generation are only used by production builds and production servers. Rakun initialization runs in parallel with development code compilation to reduce cold-start latency.

Normal web pages automatically include the Rakun development toolbar. It shows route and document metadata, links to the configured manager, lists rendered layout/template/content modules, highlights their wrapper-free DOM roots, and inspects the props received by each module. It follows client-side Bun navigation and reload updates. Manager preview pages keep their dedicated inspection flow and do not mount this toolbar. Production output contains neither the toolbar bundle nor its instrumentation markers.

rakun-bun build displays the current phase and elapsed time while it loads configuration, bundles code, renders static routes, creates the production server, and analyzes the output. Interactive terminals use a spinner; redirected output and CI receive stable log lines without terminal control codes.

The command writes:

dist/
  server.js
  assets/
  routes/
  manifests/
    build.json
    client.json
    modules.json
    routes.json

The build report includes elapsed time and lists prerendered routes with their HTML, flight, raw client asset, and gzip transfer sizes, followed by each client bundle with its raw and gzip sizes, runtime routes, the manager's initial payload and complete lazy output, server bundle, and total output size. Large route and bundle lists keep their first and last entries and collapse the middle. The programmatic RakunBunApplication.build() result exposes the same per-route asset and byte metadata through routes.

Run the production output with rakun-bun start or bun dist/server.js. Production assets are gzip-compressed on demand with Bun's native compressor when the browser advertises support through Accept-Encoding. Compressed bytes use the bounded memory cache, while development serves the original files to keep rebuilds immediate.

await app.stop() closes HTTP, file watchers, MongoDB, hydrated collaboration documents, and Bun's memory caches. Applications started with startRakunBun() also perform this graceful cleanup for SIGTERM and SIGINT, including Railway deployment shutdowns.

Public API

  • RakunBunConfig, RakunBunCacheOptions, RakunBunCssOptions, RakunBunDocumentProps, loadRakunConfig(), and resolveRakunConfig()
  • createRakunBun() and startRakunBun()
  • RakunBunApplication.build(), .fetch(), .serve(), .invalidatePath(), and .stop()
  • discoverRakunModules()
  • createBunPlatform()
  • Link and usePathname() for Bun client navigation
  • RakunRouteCache and RakunRouteCacheOptions

The web config hook can replace direct core reads for a remote or test data source. Normal monolithic applications should use bootstrap and let the adapter call core directly.