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

allow-parse

v0.1.0

Published

Zero-dependency HTTP Allow header parser and serializer for Node.js

Readme

allow-parse

Zero-dependency HTTP Allow header parser and serializer for Node.js — RFC 9110 §9.2.2.

npm version license node tests zero deps

Why allow-parse?

Node.js developers building REST API servers, CORS preflight handlers, API gateways, and HTTP debugging tools need to parse the HTTP Allow header — the standard response header that tells clients which HTTP methods are permitted for a resource (used in every OPTIONS response, CORS preflight, COOP/COEP policy discovery, and resource capability query). Today, every developer hand-rolls methods.split(',').map(m => m.trim().toUpperCase()) with ad-hoc error handling — or pulls in a heavy framework. There is no zero-dependency, RFC-compliant, typed parser for this header.

allow-parse closes the gap with a small, well-tested, zero-dependency library covering parse and serialize end-to-end.

import { parseAllow, serializeAllow, InvalidAllowHeader } from 'allow-parse';

// Parse an Allow header
const methods = parseAllow('GET, POST, OPTIONS');
methods.has('GET'); // → true

// Serialize back to a header value
serializeAllow(new Set(['GET', 'POST'])); // → 'GET, POST'

// Case-insensitive (HTTP convention: uppercase)
parseAllow('get, post'); // → Set { 'GET', 'POST' }

// Structured failures, never uncaught exceptions
try { parseAllow(''); } catch (e) { /* InvalidAllowHeader */ }

Quick start

npm install allow-parse
import { parseAllow, serializeAllow } from 'allow-parse';

const allowHeader = 'GET, POST, OPTIONS, DELETE';
const methods = parseAllow(allowHeader);              // Set<string>
const serialized = serializeAllow(methods);           // 'DELETE, GET, OPTIONS, POST'
const reparsed = parseAllow(serialized);              // same Set (dedup + re-ordered is fine)

⚡ Performance & Benchmarks

allow-parse trades ~1 μs per call (vs. the naive methods.split(',').map(m => m.trim().toUpperCase()) pattern) for input validation, structured failures, and RFC-9110 compliance. The naive reference is faster but silently accepts malformed input — the exact bug class this library exists to prevent. Run the benchmark locally to reproduce:

node benchmarks/run_benchmark.js

The full matrix lives in benchmarks/BENCHMARK.md (12 workload profiles × 5 iterations each = 60 measurements per implementation, mean + p95 microseconds reported).

| Workload | allow-parse mean (μs) | manual .split().map() mean (μs) | Ratio (ours/naive) | |---|---:|---:|---:| | Single method ('GET') | 2.31 | 0.29 | 7.92× | | 3 methods ('GET, POST, OPTIONS') | 1.12 | 0.39 | 2.85× | | 9 standard methods (full RFC set) | 3.69 | 0.75 | 4.92× | | 100 methods (stress) | 7.27 | 4.22 | 1.72× | | 1000 methods (stress) | 77.76 | 45.60 | 1.71× | | With leading/trailing whitespace | 0.42 | 0.35 | 1.21× | | Malformed (empty string, throws) | 1.73 | 1.32 | 1.31× | | Malformed (double comma, throws) | 2.78 | 0.27 | 10.43× | | Round-trip (serialize → parse) | 3.67 | 1.68 | 2.18× | | 1000-method Set serialize | 5.36 | 3.88 | 1.38× | | Case normalization ('get, post') | 0.60 | 0.28 | 2.12× | | 100 small parses in a loop | 21.49 | 9.83 | 2.19× |

Reproduce: node benchmarks/run_benchmark.js — exit 0 on success, regenerates benchmarks/BENCHMARK.md and benchmarks/results.json. Numbers above reflect Node v22 on Linux/arm64. Run-to-run variance is ~5–10%.

Honest summary: allow-parse is not faster than the naive reference on typical small inputs because input validation has a constant cost. On large inputs (≥100 methods) it pulls ahead because V8's JIT-compiled regex outperforms the naive .map().filter() chain. On malformed inputs both are comparably fast, but allow-parse returns structured InvalidAllowHeader while the naive reference throws generic TypeError. For production HTTP middleware the ~1 μs cost is negligible (<0.01% of a typical request budget).

API

parseAllow(header) => Set<string>

Parse an RFC 9110 §9.2.2 Allow header value into a Set of uppercase method names.

  • Lowercase methods are normalised to uppercase (HTTP methods are case-insensitive; this library canonicalises per common convention).
  • Surrounding whitespace and whitespace around commas are stripped.
  • Empty segments (e.g. 'GET,,POST') raise InvalidAllowHeader.
  • Non-letter characters (digits, /, -, _, etc.) raise InvalidAllowHeader — only uppercase ASCII letters (AZ) are accepted as method tokens per RFC 9110 method grammar.
  • null, undefined, and non-string inputs raise InvalidAllowHeader (total API over arbitrary input).
parseAllow('GET, POST, OPTIONS');        // Set { 'GET', 'POST', 'OPTIONS' }
parseAllow('  GET  ,  POST  ');          // Set { 'GET', 'POST' }
parseAllow('get, post');                 // Set { 'GET', 'POST' }
parseAllow('');                          // throws InvalidAllowHeader
parseAllow('GET,,POST');                 // throws InvalidAllowHeader
parseAllow('HTTP/1.1 OPTIONS');          // throws InvalidAllowHeader
parseAllow(null);                        // throws InvalidAllowHeader

serializeAllow(methods) => string

Serialize a Set of uppercase method names back into an Allow header value. Uses ', ' (comma-space) as the separator.

  • The set MUST be non-empty (empty set → InvalidAllowHeader).
  • Every entry MUST be a string of uppercase ASCII letters (lowercase/mixed/digits/symbols → InvalidAllowHeader). This matches the convention of constructing headers from canonicalised inputs.
  • Non-Set inputs raise InvalidAllowHeader (e.g. arrays, strings, Maps).
serializeAllow(new Set(['GET', 'POST']));            // 'GET, POST'
serializeAllow(new Set(['GET']));                    // 'GET'
serializeAllow(new Set(['GET', 'POST', 'DELETE']));  // 'GET, POST, DELETE'
serializeAllow(new Set());                           // throws InvalidAllowHeader
serializeAllow(new Set(['get']));                    // throws InvalidAllowHeader
serializeAllow(['GET']);                             // throws InvalidAllowHeader

InvalidAllowHeader extends Error

Custom error class for all validation failures. Always checkable as both instanceof InvalidAllowHeader and instanceof Error. Has a .name === 'InvalidAllowHeader' and a descriptive .message.

try {
  parseAllow('');
} catch (e) {
  if (e instanceof InvalidAllowHeader) {
    // structured failure path
  } else {
    throw e; // unexpected
  }
}

Module formats

allow-parse ships dual ESM + CommonJS:

// ESM
import { parseAllow, serializeAllow, InvalidAllowHeader } from 'allow-parse';
// CommonJS
const { parseAllow, serializeAllow, InvalidAllowHeader } = require('allow-parse');

package.json declares both "main" (CJS bridge at src/index.cjs) and "exports" (ESM at src/index.js) plus index.d.ts for TypeScript consumers.

CLI

allow-parse ships a bin/cli.js for shell pipelines and ad-hoc testing:

# Parse an Allow header
$ node bin/cli.js "GET, POST, OPTIONS"
GET, POST, OPTIONS

# Read from stdin (empty stdin → structured failure, exit 1)
$ echo "get, post" | node bin/cli.js
GET, POST

# Serialise a Set of method names
$ node bin/cli.js --serialize GET POST OPTIONS
GET, POST, OPTIONS

# Help
$ node bin/cli.js --help
allow-parse — RFC 9110 Allow header parser & serializer
...

The CLI is total over arbitrary input: any malformed input prints a structured InvalidAllowHeader error and exits with code 1. Never throws an uncaught exception (Invariant 21).

TypeScript

TypeScript types are shipped at src/index.d.ts:

import { parseAllow, serializeAllow, InvalidAllowHeader } from 'allow-parse';

const methods: Set<string> = parseAllow('GET, POST');
const header: string = serializeAllow(methods);

Install

# Local install from this checkout (development):
npm install /root/projects/allow-parse

# Once published to the public registry:
npm install allow-parse

Zero runtime dependencies. Single ~100 LOC source file. Total test suite: 163 tests (147 library + 16 CLI), all passing.

Compatibility

  • Node.js ≥ 18 (ESM and CommonJS both work via package.json exports).
  • TypeScript types included.
  • Zero runtime dependencies.

Limitations & non-goals

  • allow-parse does not validate HTTP methods against a fixed list — any uppercase ASCII letter sequence is accepted per RFC 9110 (extension methods like LOCK, MOVE, VIEW work). This is a deliberate design choice.
  • BOM handling: Input is passed through JavaScript's String.prototype.trim() before parsing. Per ECMA-262 §22.1.3.31, trim() consumes U+FEFF BOM characters at the start/end of the string. A header value of '\uFEFFGET' parses successfully as Set { 'GET' }. RFC 9110 does not address BOM handling; this behaviour follows the ECMAScript language spec.
  • The parser canonicalises lowercase input to uppercase. The serializer requires already-uppercase input (no implicit normalisation on the write path). This mirrors the typical pattern in server code where input is canonicalised once at the boundary.
  • allow-parse does not implement HTTP method execution, routing, or CORS policy enforcement — it only parses and serialises the header value.
  • Output order from serializeAllow reflects Set insertion order; it does not sort or rank methods.
  • Out-of-spec characters that some HTTP libraries tolerate (digits, _, .) are rejected. RFC 9110 method grammar permits a broader token set; this library takes the conservative interpretation that method tokens are uppercase ASCII letters only (consistent with how jshttp-style libraries parse other headers like Accept and Vary).

License

MIT — see LICENSE.