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

@flarecart/worker-http

v1.0.0

Published

The HTTP layer of a Cloudflare Worker API — a URLPattern router with per-route CORS, ApiError responses, request helpers (IP and /64, country, bearer, cookies, size-capped JSON with any Zod-shaped schema), safe cookies, origin checks and Turnstile.

Readme

@flarecart/worker-http

The HTTP layer of a Cloudflare Worker API: a small URLPattern router where each route carries its own CORS policy, errors that answer themselves, and the request helpers every Worker ends up writing (the client's IP and country, a bearer token, a cookie, a size-capped JSON body checked against a schema). Plus safe cookies, origin checks and Turnstile.

No framework, no dependencies. It answers the API and gets out of the way: an unknown path resolves null, so the Worker can serve its static assets.

npm install @flarecart/worker-http

Why

A Worker API grows the same plumbing every time, and the details are where the bugs live:

  • CORS belongs beside the route. A webhook must never answer a browser, a storefront endpoint answers your site only, and a bearer-token endpoint can answer any page (it never uses cookies). A list of rules somewhere else drifts from the routes it describes.
  • Errors should be data. A handler throws forbidden('…', 'CODE') and the caller gets { error: { code, message } } with the right status and headers. A library's own errors (a refused API key) map to one through onError. Everything else is a bug: logged, and answered with a 500 that leaks nothing.
  • IPv6 clients own a /64. Counting single addresses hands an attacker 2⁶⁴ fresh limits; ipPrefix counts the network.
  • A body is read once, and capped. readJson refuses an oversized body by its declared length and then its real one (a client can lie), and names the first invalid field.

Features

  • 🧭 Router on the standard URLPattern, with params, preflights and 405 + Allow
  • 🌐 CORS per route: site (your origins), any (bearer-token APIs), none (webhooks)
  • 🧯 ApiError: status, code, human message, headers (Retry-After), details
  • 🔌 onError to map a library's errors; bugs become a logged, generic 500
  • 🛰️ Request helpers: IP, IPv6 /64, country (no Tor/unknown), user agent, bearer, cookie, query, Accept
  • 📦 readJson: size-capped, validated by any Zod-shaped schema (Zod is not a dependency)
  • 🍪 Cookies: HttpOnly; Secure; SameSite=Strict by default; header-splitting values refused
  • 🛡️ Origin checks and Turnstile verification
  • 📄 htmlPage: an escaped, CSP-locked page for people who follow links

Usage

import { createRouter, route, readJson, notFound, notConfigured, originList } from '@flarecart/worker-http';
import { z } from 'zod';

const Body = z.object({ email: z.email() });

const routes = [
	route('POST', '/api/checkout', 'site', async (ctx) => {
		const { email } = await readJson(ctx.request, Body);
		return Response.json(await ctx.startCheckout(email));
	}),
	route('GET', '/api/orders/:id', 'any', async (ctx, { id }) => {
		const order = await ctx.findOrder(id);
		if (!order) throw notFound('No such order.');
		return Response.json(order);
	}),
	route('POST', '/api/webhooks/stripe', 'none', (ctx) => ctx.webhook()),
];

const handle = createRouter(routes, {
	allowedOrigins: (ctx) => originList(ctx.env.ALLOWED_ORIGINS),
	onError: (thrown) => (thrown?.type === 'StripeAuthenticationError' ? notConfigured('Stripe refused the key.') : null),
});

export default {
	async fetch(request, env) {
		const ctx = { request, env, /* your helpers */ };
		return (await handle(request, ctx)) ?? env.ASSETS.fetch(request);
	},
};

API

Router

| | | |---|---| | route(methods, path, cors, handler) | cors is 'site', 'any' or 'none'; handler(context, params) returns a Response. | | createRouter(routes, options?) | Returns handle(request, context) → Response, or null for an unknown path. Options: allowedOrigins (array, or a function of the context), onError(thrown) → ApiError \| null, log, cors (allowHeaders, exposeHeaders, maxAge). |

Errors

new ApiError(status, code, message, headers?, details?), and badRequest, unauthorized, forbidden, notFound, conflict, tooLarge, tooMany(message?, retryAfter?), notConfigured.

Responses

json(data, status?, headers?), noContent(headers?), errorResponse(error), internalError(), htmlPage(status, title, message), corsHeaders(origin, options?), withHeaders(response, headers), BASE_HEADERS (nosniff, no-store, no-referrer).

Requests

getIp, ipPrefix, maskIp (203.0.113.x, for a sign-in history), getCountry, getUserAgent(request, max?), getOrigin, getBearerToken, getCookie(request, name), getQueryParam(request, name), wantsHtml, readJson(request, schema, maxBytes?).

Cookies, origins, Turnstile

serializeCookie(name, value, options?), clearCookie(name, options?), originOf(url), originList(sites), checkOrigin(request, allowed, message?), verifyTurnstile(token, { secret, ip?, fetch? }), requireTurnstile(request, token, { secret, fetch? }), escapeHtml.

Notes

  • URLPattern is built into Workers, Deno, browsers and Node 23.8+. On Node 22, load a polyfill (urlpattern-polyfill) before the router.
  • getIp and getCountry trust CF-Connecting-IP and request.cf, which Cloudflare sets. Behind anything else, read your own trusted header.
  • any is only safe for endpoints that authenticate with a bearer token. An endpoint that reads a cookie must be site or none.
  • requireTurnstile is a no-op without a secret, so Turnstile can be switched on by setting one.

License

MIT