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

@arachnejs/kit

v0.4.1

Published

Arachne app kit: static, server and API apps, SSR, prerendering, dev server with hot reload, CLI

Readme

@arachnejs/kit

Build static sites, server-rendered apps and API-only services from one project layout, with a dev server that reloads as you type. See ADR 0015.

bunx @arachnejs/kit create my-app --template server   # or static | api
cd my-app && bun install && bun run dev

The CLI is arachne: inside a project, bunx arachne …; elsewhere, bunx @arachnejs/kit … (the unscoped arachne package on npm is unrelated).

Project layout

arachne.config.ts   defineConfig({ … })          optional
app/routes.tsx      export const routes = [...]   pages (shared by server and browser)
app/server.ts       export default defineServer(…) API, loaders, middleware (server only)
public/             copied as-is (favicon, robots.txt, images)

| Mode | When | Output | |---|---|---| | static | mode: "static", or pages without app/server.ts | dist/**/index.html, dist/_data/**.json, dist/assets/*, 404.html, sitemap.xml — host anywhere | | server | pages + app/server.ts (default) | dist/client/* + dist/server/index.js (run with Bun) | | api | no app/routes.tsx, or mode: "api" | dist/server/index.js |

Pages

app/routes.tsx exports routes for @arachnejs/router: nested layouts, lazy routes, head. Optional exports: NotFound (404 page) and ErrorPage (loader errors; receives props.error with status/message). Both render inside the root / matched layouts.

export const routes: RouteDefinition[] = [
  {
    path: "/",
    component: Layout,                          // props.children = the page
    children: [
      { path: "", component: Home, head: { title: "Home" } },
      { path: "blog/:slug", component: Post, head: ({ data }) => ({ title: (data as Post).title }) },
    ],
  },
];

Pages are rendered on the server (or at build time), then hydrated: the browser adopts the HTML, and <Link>s / plain <a href>s navigate on the client, fetching each page's data as JSON. Page data carries the build it came from: after a deploy, a tab still running the previous build loads the next page in full instead of mixing old code with new data.

Server

// app/server.ts
export default defineServer(async ({ dev, mode, config }) => {
  const db = createDb({ dialect: sqlite({ path: "data/app.db" }), tables });
  const auth = createAuth({ db, mailer, baseUrl: process.env.BASE_URL!, secret: process.env.AUTH_SECRET });
  await auth.setup();
  return {
    middleware: [auth.middleware()],
    routes: [...auth.routes(), ...api],            // @arachnejs/server routes
    openapi: { title: "My API", version: "1.0.0" }, // → /openapi.json, /docs
    loaders: {                                      // by route id (= full pattern)
      "/blog/:slug": async ({ params, ctx }) => (await posts.find(params.slug)) ?? notFound(),
    },
    paths: { "/blog/:slug": async () => (await posts.all()).map((p) => ({ slug: p.slug })) }, // static builds
    db, tables,                                     // for `arachne migrate`
    dispose: () => db.close(),
  };
});
  • Loaders run on the server for the first load and behind GET /__arachne/data/<path> for client navigations (static builds: at build time, saved as _data/<path>.json). ctx.state.user is available after auth middleware. Throw HttpError(404) for missing records.
  • The factory runs once at boot; in static mode only at build time.

Configuration

export default defineConfig({
  mode: "server",                               // static | server | api
  base: "/",                                    // e.g. "/docs/" for sub-path deploys
  title: { template: "%s · Site", default: "Site" },
  styles: ["app/styles.css"],                   // bundled, minified, hashed
  head: `<link rel="icon" href="%base%favicon.svg">`,
  hydrate: true,                                // false = zero-JS static pages
  siteUrl: "https://example.com",               // sitemap.xml
  lang: "en",
  port: 3000,                                   // PORT env wins
  server: { bodyLimit: 1_048_576, trustProxy: false, securityHeaders: {} /* or false */ },
  mcp: { name: "my-app", version: "1.0.0" },    // POST /mcp for routes with `mcp: true`
  migrations: { dir: "migrations" },
  document: (parts) => `<!doctype html>…`,      // custom HTML shell
});

Security headers (CSP with a per-request nonce, HSTS, nosniff, …) are on by default in server mode.

Development

arachne dev serves from source:

  • Component/page edits rebuild the client and SSR bundles and reload the browser; CSS edits swap stylesheets in place; build errors show an overlay and recover on the next save.
  • Edits to anything app/server.ts imports (or the config) restart the server process; the browser reconnects and reloads. So does creating or deleting app/server.ts or app/routes.tsx, which changes the mode.
  • Dev builds warn in the console about hydration mismatches.

Build errors name the file, line and column.

Stylesheets can point at files in public/ with root URLs (url("/fonts/body.woff2")); those are left as written. Other absolute URLs that don't exist fail the build.

Build and deploy

arachne build              # mode from config
arachne build --mode static --base /docs/
arachne preview            # serve a static build locally (404.html honoured)
arachne start              # run dist/server/index.js (server/api modes)

The server bundle inlines @arachnejs/*; the app's other dependencies stay in node_modules, so deploy with bun install --production next to dist/.

CLI

| Command | Description | |---|---| | arachne dev [--port] | dev server with hot reload | | arachne build [--mode] [--out] [--base] | production build | | arachne start [--port] / arachne preview [--port] | run a build | | arachne create <dir> --template static\|server\|api | new project | | arachne routes | list pages and API routes | | arachne openapi [--out file] | OpenAPI document | | arachne migrate [up\|down\|status\|generate] [--steps n] [--name x] | migrations (db/tables from app/server.ts) |

Templates

  • templates/static — editorial blog, build-time data, sitemap
  • templates/server — accounts (sign-up, verification, reset), per-user notes with ACL, typed API client, OpenAPI, MCP
  • templates/api — projects API: API tokens, validation, pagination, uploads, CORS, rate limits, OpenAPI, MCP

Programmatic API

createAppServer({ root, dev }) (in-memory build + fetch/listen), build(root, options), preview({ dir }), startDevServer({ root }), resolveConfig(root), defineConfig, defineServer.

MCP

arachne_kit_config, arachne_kit_routes, arachne_kit_build and arachne_kit_create (both need confirm: true), arachne_kit_api_summary.

Testing

bun test covers config, SSR, data endpoints, static builds, templates (including production bundles run as processes) and hot reload. bun run e2e drives Chromium through the fixture (static, SSR, dev) and the full-stack template.