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

@aiquants/request-isolation

v0.1.0

Published

Host-agnostic cross-origin check for server routes: one decision over Fetch Metadata and Origin, taken before authentication, that refuses requests started by a page of another origin (sibling subdomains included) unless the route serves that top-level do

Readme

@aiquants/request-isolation

Host-agnostic cross-origin check for server routes. One function, crossOriginRefusal, decides from Fetch Metadata (Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest) and Origin whether a request was started by a page of another origin, so a route can refuse it before authentication, rate charges, authorization or any other work.

  • Refuses every request from another origin, a sibling subdomain of the same site included, whatever its method.
  • Serves a top-level document navigation from another origin (a link to the route) only when the route says it does.
  • Decides a request without Fetch Metadata by its method and, for a method that may change state, by its Origin.

Zero runtime dependencies. Works anywhere WHATWG Request and URL.canParse exist (Node.js 18.17 or later, Deno, Bun, edge workers).

Contents

Why a request-side check

| What one might rely on | Why it does not stop a cross-origin request | | --- | --- | | SameSite=Lax session cookies | A sibling subdomain of the same site is the same site, so its requests carry the cookie | | CORS | A form submission (application/x-www-form-urlencoded, multipart/form-data, text/plain) and a no-cors request need no preflight; the request runs and only the response is hidden | | Response headers (Cross-Origin-Resource-Policy, X-Frame-Options, ...) | They decide whether a page may read or render the response, not whether the request runs | | A framework's built-in CSRF check | Frameworks usually check document requests and their own data requests; resource routes (APIs, streams, downloads) pass through |

The check is therefore made on the request, in one place, first. It is written as an allow-list: a frame, an embedded object, a navigation without a destination and any destination a future specification adds are refused by construction, because only the cases below are served.

The rule

| Request | Answer | | --- | --- | | Sec-Fetch-Site: same-origin or none (a load the user started: address bar, bookmark) | Served, whatever the method | | Sec-Fetch-Site with any other value (same-site, cross-site, a value the specification does not define), top-level document navigation (GET, Sec-Fetch-Mode: navigate, Sec-Fetch-Dest: document) that policy.navigable(request) answers with true | Served | | Sec-Fetch-Site with any other value, anything else | Refused: "cross-origin-fetch" | | No Sec-Fetch-Site, a safe method (GET, HEAD, OPTIONS) | Served | | No Sec-Fetch-Site, a method that may change state, no Origin or an Origin naming the request's own host (with its port) | Served | | No Sec-Fetch-Site, a method that may change state, any other Origin (another host or port, null, a value that is not a URL) | Refused: "foreign-origin" |

Without Fetch Metadata the rule is the one of Go 1.25's net/http CrossOriginProtection. With Fetch Metadata it is stricter: a request from another origin is refused even when its method is safe (a sibling page cannot open a stream, probe a download or load an image from the route), except the document navigations the route serves.

Install

pnpm add @aiquants/request-isolation

In a pnpm workspace, depend on it with "@aiquants/request-isolation": "workspace:^".

Usage

A route that no page of another origin may open (an API, an action, a stream):

import { crossOriginRefusal, NO_CROSS_ORIGIN_NAVIGATION } from "@aiquants/request-isolation"

export async function action({ request }: { request: Request }): Promise<Response> {
    if (crossOriginRefusal(request, NO_CROSS_ORIGIN_NAVIGATION) !== undefined) {
        return new Response(JSON.stringify({ error: "Cross-site request rejected" }), {
            status: 403,
            headers: { "Content-Type": "application/json", "Cache-Control": "no-store" },
        })
    }
    // authenticate, charge, authorize, then do the work
}

A route whose links may be opened from another origin (an original file shown in a new tab, say), and only for the requests it chooses:

import { type CrossOriginPolicy, crossOriginRefusal } from "@aiquants/request-isolation"

const ORIGINAL_FILE_LINKS: CrossOriginPolicy = {
    navigable: (request) => new URL(request.url).searchParams.get("disposition") === "inline",
}

export async function loader({ request }: { request: Request }): Promise<Response> {
    const refusal = crossOriginRefusal(request, ORIGINAL_FILE_LINKS)
    if (refusal !== undefined) {
        console.warn(`cross_origin_refused reason=${refusal} method=${request.method}`)
        return new Response("Forbidden", { status: 403, headers: { "Cache-Control": "no-store" } })
    }
    // ...
}

The refusal value never contains anything the request sent, so it can be logged as it is. Log header values the request sent only after bounding and quoting them.

API

crossOriginRefusal(request, policy)

function crossOriginRefusal(request: Request, policy: CrossOriginPolicy): CrossOriginRefusal | undefined

Returns why the request must be refused, or undefined when the route may serve it (see The rule). policy.navigable is called only for a GET document navigation from another origin, with the same Request, and the navigation is served only when it returns exactly true; any other answer refuses it.

Throws TypeError when policy is not an object whose navigable is a function. The policy is checked on every call, before the request is read, so a missing policy fails on the first request rather than on the first cross-origin navigation.

CrossOriginPolicy

type CrossOriginPolicy = { readonly navigable: (request: Request) => boolean }

The route's answer to the one question the check asks it: does it serve this top-level document navigation from another origin?

NO_CROSS_ORIGIN_NAVIGATION

A frozen CrossOriginPolicy whose navigable always returns false: the policy of a route that no page of another origin may open.

CrossOriginRefusal

type CrossOriginRefusal = "cross-origin-fetch" | "foreign-origin"

| Value | Meaning | | --- | --- | | "cross-origin-fetch" | Fetch Metadata names another origin and the request is not a document navigation the route serves | | "foreign-origin" | No Fetch Metadata, a method that may change state, and an Origin that does not name the request's host |

Security notes

  • Run it first. Call the check before authentication, session refresh, rate limiting, authorization and any service call, and answer a refusal without Set-Cookie, so a refused request leaves no trace on the session or the quotas.
  • The request URL's host is the reference. Origin is compared with the host of request.url, which the server adapter builds from the Host header. Behind a reverse proxy, make sure the URL the route sees carries the host the browser addressed.
  • Requests without Fetch Metadata. Browsers send Fetch Metadata only to potentially trustworthy URLs (https:, or http: to a loopback host). A request without it comes from a client that is not a browser, an older browser, or a page served over plain HTTP. Browsers always send Origin with a request whose method may change state (the value may be null), so its absence means no page started the request.
  • Method names are compared as sent. WHATWG Request upper-cases only the standard methods (get, post, ...); a non-standard spelling such as patch stays as written and is treated as a method that may change state.
  • Sign-out is a different rule. A sign-out link followed by the user from a sibling subdomain should usually still sign out, and a speculative request (prefetch, prerender) should not. Keep a separate rule for sign-out; this check is for a route's data requests.

Out of scope

  • Response headers, CORS, authentication, session handling and rate limiting.
  • Framework data-request handling (for example refusing a framework's own data-request form of a streaming route); that is the route's policy.
  • Logging and the 403 response; both stay with the route, which knows its response shape.

License

MIT