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

ordner

v0.5.3

Published

A simple file-based router for Polka

Downloads

2

Readme

Ordner

A simple file-based router for Polka inspired by Sapper and Svelte Kit.

Image

("Ordner" is German and means "folder")

Note: This is an ES6 module.

  1. Install
  2. Usage
  3. Logging
  4. Params
  5. Handlers
  6. Middlewares
  7. Hook
  8. Hook Recipes

Install

npm install ordner

Usage

Create your folder structure:

src/
├─ routes/
│  ├─ users/
│  │  ├─ index.js
│  │  ├─ :id.js
├─ index.js

Import Ordner and call it with the path of your folder containing the routes as the first argument and your Polka instance as the second one. It returns a promise that resolves when all routes have been mounted:

import polka from "polka";
import ordner from "ordner";

const server = polka();

await ordner("./src/routes", server);

server.listen(3000, () => {
  console.log(`> Running on localhost:3000`);
});

Note: Make sure to enable ES6 modules project wide by including the following line in your package.json:

type: "module",

Logging

By default Ordner prints a list of all route handlers and middlewares it found in the specified folder and in the order they are applied to your Polka instance. If you wish to disable logging, e.g. in production, you can pass in an object as the third argument and and set logging to false:

await ordner("./src/routes", server, { logging: false });

Params

To use parameters in your routes simply name your folders and files accordingly. See also Polka's docs.

routes/
├─ blog/
│  ├─ :slug.js
├─ products/
│  ├─ :id.js
├─ users/
│  ├─ :id/
│  │  ├─ index.js
│  │  ├─ orders.js
│  ├─ index.js

Handlers

You export handlers from your .js files and name them according to their HTTP method in lowercase. Since delete is a reserved keyword in JavaScript, export a function called del instead to handle DELETE requests.

Middlewares

To use middlewares every file can export an array named useBefore. Middlewares included in this array will be applied before any handler in the current file.

import { json } from "@polka/parse";

export const useBefore = [json()];

To use middlewares before a specific handler you can export arrays named useBeforePost, useBeforeGet, useBeforePut, useBeforePatch, and useBeforeDel.

import { json } from "@polka/parse";

export const useBefore = [json()];

export function get(req, res) {
  res.end("Hello Ordner!");
}

export const useBeforePut = [(req, res, next) => next()];

export function put(req, res) {
  res.end("updated");
}

Hook

You can optionally pass a hook function to Ordner which is essentially a wrapper around yout handlers. It allows you easily execute additional code before and after each or just a few specific handlers. The hook function takes the handler as its only argument and returns a function with the res and req signature:

import polka from "polka";
import ordner from "ordner";

const hook = (handler) => async (req, res) => {
  res.setHeader("Content-Type", "application/json");

  await handler(req, res);

  console.log("Request completed.");
};

await ordner("./src/routes", server, { hook });

server.listen(3000, () => {
  console.log(`> Running on localhost:3000`);
});

Note 1: You must call handler inside your hook function.

Note 2: The hook is only applied to request handlers not middlewares.

Hook Recipes

  1. Sending responses like in Svelte Kit
  2. Obscuring IDs from your database

Sending responses like in Svelte Kit

To handle responses similar to how you would in Svelte Kit, put the following code into your hook function:

const hook = (handler) => async (req, res) => {
  const { status = 200, headers = {}, body } = await handler(req);

  res.writeHead(status, {
    ...headers,
    "Content-Type": "application/json",
  });

  res.end(JSON.stringify(body));
};

Now you can simply return a { status, body, headers } object from your handlers:

export function get(req) {
  return {
    body: { message: "Hello Ordner!" },
  };
}

Obscuring IDs from your database

Another useful thing you can do with hook is obscuring IDs from your database. Database IDs are usually sequential numbers. Displaying them in your URLs like /products/17 might tempt your visitors to play around with them in a way you do not want them to. You can use the hook function to encode all IDs to something that looks more random before sending a response and decode them again when recieving requests.

// helper function to modify objects even if they contain other objects or arrays
function modifyObj(obj, fn) {
  Object.keys(obj).forEach((key) => {
    const value = obj[key];

    if (value !== null && typeof value === "object") {
      return modifyObj(value, fn);
    }

    if (Array.isArray(value)) {
      return value.forEach((obj) => modifyObj(obj, fn));
    }

    fn(key, obj);
  });
}

function decode(obj) {
  modifyObj(obj, (key, obj) => {
    if (key === "id" || key.endsWith("_id")) {
      obj[key] = Number(Buffer.from(obj[key], "base64").toString("ascii"));
    }
  });
}

function encode(obj) {
  modifyObj(obj, (key, obj) => {
    if (key === "id" || key.endsWith("_id")) {
      obj[key] = Buffer.from(String(obj[key])).toString("base64");
    }
  });
}

const hook = (handler) => async (req, res) => {
  // decode the ID from the incoming request
  decode(req.params);

  // handle the request by the corresponding handler
  let { status = 200, headers = {}, body } = await handler(req);

  // encode all IDs
  encode(body);

  // send the response
  res.writeHead(status, {
    ...headers,
    "Content-Type": "application/json",
  });

  res.end(JSON.stringify(body));
};

Create the following route:

/students/:id.js

const students = [
  {
    id: 173,
    first_name: "Tony",
    last_name: "Stark",
    school_id: 19,
  },
];

export function get(req) {
  const student = students.find(({ id }) => id === req.params.id);

  return {
    body: student,
  };
}

A GET request to /students/MTcz will now return the following response:

{
  "id": "MTcz",
  "first_name": "Tony",
  "last_name": "Stark",
  "school_id": "MTk="
}

The above example uses base 64 encoding. You can also use something like Hashids instead, which is more difficult for others to decode.