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

site-to-api-runtime

v0.1.4

Published

Small runtime for clients generated by site-to-api: cookie jar, retries, session hooks and HTML extraction. Runs on Node, Bun, browsers and edge workers.

Readme

site-to-api-runtime

The small runtime that clients generated by site-to-api gen import: a cookie jar, fetch with sessions and retries, and HTML or text extraction. It uses only web-standard APIs (fetch, Request, Headers, URL), so it runs on Node 22.12+, Bun and edge workers. Its only dependencies are zod (as zod/mini) and, outside browsers, htmlparser2 with domhandler, css-select and domutils.

You rarely call it directly: createSiteClient and the per-host factories in a generated client wire it up. This page lists everything it exports; how to use a generated client in an app is in using the client.

npm install site-to-api-runtime zod

Builds

  • The default build parses HTML with the platform's DOMParser when there is one and with htmlparser2 otherwise.
  • The browser build, which bundlers pick through the browser export condition, parses HTML with DOMParser only, so no HTML parser is bundled. :contains("text") selectors, which build writes for label rows, :scope + tr sibling selectors and table > tr rows (the parser adds a <tbody> the page did not write; it is unwrapped) read the same on both, and the tests run every HTML case on both. One difference remains: misnested markup (a <div> inside a <p>) is repaired by the browser's HTML5 parser and kept as written by htmlparser2, so a selector through such nesting can match on one and not the other.

Cookies

new CookieJar(options?) stores cookies from responses and produces the Cookie header for requests, following RFC 6265 (domain and path matching, expiry, Secure, host-only cookies).

| Member | What it does | | --- | --- | | setFromResponse(url, headers) | Stores every Set-Cookie of a response | | setCookieString(url, header) | Stores one Set-Cookie value; false when rejected | | set(name, value, options) | Stores a cookie you know (domain, path, expires, …) | | cookies(url) / cookieHeader(url) | The cookies a request to url sends, as objects or a header | | all(), delete(name, domain?), clear() | Inspect or remove cookies | | toJSON() / CookieJar.fromJSON(data) | Save the jar (a file, a database, a worker's storage) and restore it |

options.now replaces the clock, for tests. A saved jar holds real session cookies: never commit it.

Fetch

createFetch(options?) returns a fetch that adds the session's credentials and the jar's cookies, stores the cookies of every response (redirects included), and retries.

| Option | Default | | --- | --- | | jar | the session's jar, or a new one | | session | cookieSession(jar) | | retry | 3 attempts on 423, 429, 502, 503, 504 with backoff and Retry-After; idempotent methods only unless unsafe; false sends once | | fetch | globalThis.fetch | | defaultHeaders | none; added to requests that do not set them | | redirects | jar follows redirects itself so cookies of each hop are kept; native leaves them to the platform (browsers) | | credentialHeaders | header names dropped, like authorization and cookie, when a redirect leaves the origin | | onRequest, onResponse | hooks for logging |

Sessions

A Session is { jar?, prepare(request), onAuthFailure(response, request) }.

  • cookieSession(jar): sends the jar's cookies; the default.
  • tokenSession({ getToken, header?, scheme?, refresh?, refreshOn?, jar? }): sends a token (Authorization: Bearer … by default) and calls refresh once on 401.
  • browserSession({ jar, bootstrap, refreshOn? }): bootstrap loads the site in a real browser (for example Playwright) and returns its cookies; they are reused for plain HTTP and fetched again on 401 or 403. Returns the session with refresh().
  • combineSessions(...sessions): several at once (browser cookies plus a token); they must share one jar.

Errors

SiteApiError (status, statusText, url, method, body) is a failed HTTP call; isSiteApiError(value) tells one apart from other errors.

Extraction

  • extract(text, spec): records from an HTML or text response, following an ExtractSpec that build inferred and verified against the captured samples. HTML specs select records and fields with CSS selectors; text specs split delimited rows or match a regular expression with named groups. Values are coerced to the field type; a missing required field is null.
  • extractValue(html, { selector, attr, pattern }): one value, such as a CSRF token in a meta tag.
  • Types: ExtractSpec, HtmlExtractSpec, TextExtractSpec, ExtractField, FieldType, ExtractedRecord, HtmlValueLocation, and HtmlEngine, the interface both HTML parsers implement.

Both throw a TypeError for an invalid selector or pattern. Generated clients wrap them in typed parsers (extractDealsFromGetDeals(text)) that validate the records with Zod.

Used by generated code

  • requestValidationInput(data, mixedCaseHeaders?): turns hey-api's resolved request options into a plain object a Zod schema can validate (its headers is a Headers instance).
  • graphqlQuerySerializer, fetchWithoutFragment, withoutFragment: send GraphQL operations and dispatcher functions, whose spec paths carry a #name that must not reach the site.