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

scirocco

v1.0.0

Published

add type guards to your expressjs request handlers

Readme

scirocco

add type guards to your expressjs request handlers

NOTICE: this module is currently completely untested - use with caution

idea

recurring patterns

If your have already developed a http-api, your are aware of the always returning pattern:

  1. request is recieved and checked if all necessary arguments were sent
  2. arguments get extracted
  3. magic happens
  4. result is packed in the response
  5. error evaluation
  6. response is being sent back

abstracting the pattern

This can be simplified, while also enhancing types. The following example will hash a password which is url-encoded - insecure!. Types were added sometimes to help understanding.

  1. create a SourceType and a TargetType for your callback action:
//hash.ts
export interface IHashSource { password: string; }
export interface IHashTarget { hash: string; salt: string; }
  1. create a type-guard:
//hash.ts
const HashGuard = (object: any): object is IHashSource =>
    "password" in object && typeof object.password === "string";
  1. export the guard-secured callback:
//hash.ts
import * as crypto from "crypto";
import { secure } from "scirocco";

const hash = (payload: string) => {
    const salt = crypto.randomBytes(Math.ceil(64 / 2)).toString("hex").slice(0, 64);
    return { salt, hash: crypto.createHmac("sha512", salt).update(payload).digest("hex") };
};

export const callback = secure<IHashSource, IHashTarget>(
    HashGuard, (source: IHashSource): IHashTarget => hash(source.password));
  1. import the callback and the types into your expressjs router:
// router.ts
import { Request, Router } from "express";
import { scaffold } from "scirocco";
import { callback, IHashSource, IHashTarget } from "./hash";

interface IHashResponse { hash: string; }

const router: Router = Router();
  1. scaffold the expressjs request-handler - using a construct-callback which selects the necessary request arguments (like req.query.password), the callback and a destruct-callback which reduces the result from the callback (destruct-callback is optional)
// router.ts

// construct callback
const construct = (req: Request): IHashSource => ({ password: req.query.password });

// destruct callback
const destruct = (data: IHashTarget, req: Request, res: Response): IHashResponse =>
    ({ hash: data.hash });

// hook the scaffolded callback to GET /hash
router.get("/hash", scaffold<IHashSource, IHashTarget, IHashResponse>(
    construct, callback, destruct)); 
  1. done! you now have a exception-stable, format-secure and type-asserted request handler to hash a password (NOTICE: the hashing mechanism shown here might not be secure - do not copy & paste this example for production)

full code example

// hash.ts
import * as crypto from "crypto";
import { scaffold } from "scirocco";

// transaction types - source and target
export interface IHashSource { password: string; }
export interface IHashTarget { hash: string; salt: string; }

// function which hashes passwords using sha512 and a random salt
const hash = (payload: string): IHashTarget => {
    const salt = crypto.randomBytes(Math.ceil(64 / 2)).toString("hex").slice(0, 64);
    return { salt, hash: crypto.createHmac("sha512", salt).update(payload).digest("hex") };
};

// function which checks for correct format
const HashGuard = (object: any): object is IHashSource =>
    "password" in object && typeof object.password === "string";

// callback is a guarded callback transacting an IHashSource object to IHashTarget object
export const callback = secure<IHashSource, IHashTarget>(HashGuard, (source: IHashSource) =>
    hash(source.password));
// router.ts
import { Request, Router } from "express";
import { scaffold } from "scirocco";
import { callback, IHashSource, IHashTarget } from "./hash";

// type of the response body
interface IHashResponse { hash: string; }

// initialization of the expressjs router
const router: Router = Router();


// construct callback
const construct = (req: Request): IHashSource => ({ password: req.query.password });

// destruct callback
const destruct = (data: IHashTarget, req: Request, res: Response): IHashResponse =>
    ({ hash: data.hash });

// hook the scaffolded callback to GET /hash
router.get("/hash", scaffold<IHashSource, IHashTarget, IHashResponse>(
    construct, callback, destruct)); 

error handling

errors can occur always thus they need proper handling - with this module it is very easy: you can throw any error everywhere (in the construct, guard, callback and destruct function): throw NotFoundError. This module exports a few standard errors (FormatError, ForbiddenError, UnauthorizedError, NotFoundError and ServerError), but you can also create your own (pull-request them?) if you want - just use the ErrorType which is also exported.

scaffold error-arguments

The scaffold function takes 6 arguments max. The first three are callbacks but the two after them are more interesting from an error-handling perspective:

  • invokeNextOnError: if invokeNextOnError is true, the next-callback from expressjs will be invoked if an error was thrown (it will be invoked with the error as first argument) instead of being sent back immediately - so you can add your own error-handler to the express instance. If an error was thrown which is not of the type ErrorType, the error will be wrapped into a new error object: { code: 500, status: "ServerError", error: e } where 'e' is the thrown error (only if passPureErrors is true). default=false
  • passPureErrors: select if errors that are not of the type ErrorType should be replaced with a ServerError. default=false