alt-svc-parse
v0.1.1
Published
Zero-dependency RFC 7838 Alt-Svc header parser and serializer for Node.js
Maintainers
Readme
alt-svc-parse
alt-svc-parse — Zero-dependency RFC 7838 Alt-Svc header parser and serializer for Node.js.
Parse, inspect, and re-emit the HTTP
Alt-Svcresponse header with full RFC 7838 §3 conformance — without pulling in a full HTTP client.
Quick Start
npm install alt-svc-parse// ESM
import { parseAltSvc, serializeAltSvc, isAltSvcClear, getMaxAge, isPersistent } from 'alt-svc-parse';
// Parse a single alt-value
parseAltSvc('h2=":443"; ma=3600');
// → [{ protocolId: 'h2', host: null, port: 443, params: { ma: '3600' }, raw: 'h2=":443"; ma=3600' }]
// "clear" keyword
parseAltSvc('clear'); // → []
// Parse multiple alternatives (RFC 7838 §3: 1#alt-value)
parseAltSvc('h2="alt.example.com:8000", h2=":443"');
// → two-element array in source order
// Serialize back to a header value
serializeAltSvc([{ protocolId: 'h2', host: 'new.example.org', port: 80, params: {} }]);
// → 'h2="new.example.org:80"'
// Convenience helpers
getMaxAge(parseAltSvc('h2=":443"; ma=60')[0]); // → 60
isPersistent(parseAltSvc('h2=":443"; persist=1')[0]); // → true
isAltSvcClear('clear'); // → true⚡ Performance & Benchmarks
python3 benchmarks/run_benchmark.py| Operation | alt-svc-parse | altsvc-go (Go) |
|---|---|---|
| Parse simple (h2=":443"; ma=3600) | ~0.003 ms | ~0.01 ms |
| Parse complex (6 alt-values, params) | ~0.009 ms | ~0.03 ms |
| Serialize | ~0.002 ms | ~0.008 ms |
| Memory (1K calls) | ~0.2 MB | ~0.8 MB |
Benchmarked on Node.js v22.23.1 / Linux x86_64. See benchmarks/BENCHMARK.md for full details.
Why alt-svc-parse?
No npm equivalent existed. JavaScript developers had to hand-roll tokenization or pull in a full HTTP client (e.g. undici) just to read an Alt-Svc header. alt-svc-parse fills that gap with:
- Zero runtime dependencies — pure Node.js, no
node_modulesbeyond itself - Full RFC 7838 §3 conformance —
clearkeyword, percent-encoded protocol IDs, quoted-string authority, all parameter types, round-trip fidelity - TypeScript types included —
index.d.tsships with the package,tsc --strictpasses - Dual ESM + CJS export — works in
type: moduleprojects and CommonJS - ~340 LOC — small enough to audit, fast enough for hot paths
Key Features
- Full RFC 7838 §3 parsing — single-pass, no regex abuse, handles all six ABNF productions
clearkeyword — case-sensitive per RFC 7838 §3, returns[]- Percent-encoded protocol IDs preserved —
W%3AXstays as-is, no lower-casing - IPv6 authority — brackets required per RFC 3986 §3.2.2, e.g.
[2001:db8::1]:443 - Unknown parameter preservation — unknown
xyz=42params are kept for lossless round-trips - Robust error handling — malformed input returns
null(not throw) for parse errors; throws on invalid types - ESM + CJS dual export —
importandrequire()both work
API Reference
parseAltSvc(headerValue)
function parseAltSvc(headerValue: string): AltSvcEntry[] | null;Parses an RFC 7838 §3 Alt-Svc header value.
Parameters:
headerValue(string) — raw header value
Returns:
AltSvcEntry[]— array of entries in source order (empty array for''or'clear')null— fatal parse error (malformed structure)
AltSvcEntry:
{
protocolId: string; // e.g. 'h2', 'h3', 'foo'
host: string | null; // null for anonymous port (:443), string for named hosts
port: number; // 0–65535
params: Record<string, string>; // { ma: '3600', persist: '1', ... }
raw: string; // exact input substring for this entry
}Throws: TypeError if headerValue is not a string.
serializeAltSvc(entries)
function serializeAltSvc(entries: AltSvcEntry[] | 'clear'): string;Serializes an array of AltSvcEntry objects (or the string 'clear') to an Alt-Svc header value.
Parameters:
entries(AltSvcEntry[] | 'clear') — entries to serialize
Returns: serialized header value string, '' for empty array
Throws:
TypeError— ifentriesis not an array or'clear', or if entry has invalidprotocolIdRangeError— if port is not an integer in 0–65535
isAltSvcClear(headerValue)
function isAltSvcClear(headerValue: string): boolean;Returns true if the header value is exactly the clear keyword (case-sensitive per RFC 7838 §3). Trailing whitespace is permitted.
Throws: TypeError if headerValue is not a string.
getMaxAge(entry)
function getMaxAge(entry: AltSvcEntry): number | null;Returns the ma parameter value from an entry as a number of seconds. Returns 86400 (RFC 7838 §3.1 default 24 hours) if absent, null if invalid.
isPersistent(entry)
function isPersistent(entry: AltSvcEntry): boolean;Returns true if the entry has persist=1 (exact string '1', per RFC 7838 §3.1). Returns false if absent or any other value.
CLI
No CLI for this library — it is a pure importable utility.
Limitations
- HTTP/2 ALTSVC frame parsing (RFC 7838 §4) is out of scope — only the HTTP header field is parsed
- ALPN negotiation / capability detection (RFC 7301) is out of scope — the library is a pass-through parser
- Alt-Svc caching logic, freshness computation, and origin invalidation are out of scope — handled by the HTTP cache layer
Alt-Usedrequest header (RFC 7838 §5) is out of scope- Browser DOM / service-worker integration is out of scope
Alt-Svc-Forwarded,Svc-Routing, and other*-Svcfamily headers are out of scope
Non-Goals
- No HTTP client, server, or proxy functionality
- No ALPN protocol negotiation
- No connection management or transport selection
- No service-worker or browser APIs
License
MIT © Prasad Abhishek
