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

@qfetch/middleware-base-url

v0.0.0-reserved.0

Published

Fetch middleware for base URL resolution with consistent same-origin handling.

Downloads

16

Readme

@qfetch/middleware-base-url

Fetch middleware for automatically resolving URLs against a configured base URL.

Overview

Automatically resolves request URLs against a configured base URL with consistent same-origin handling. All same-origin requests (even those with absolute paths like /users) are treated as relative to the base path, while different-origin requests pass through unchanged.

This utility-first approach deviates from strict URL Standard behavior to provide a more intuitive and consistent developer experience when working with API clients.

Intended for use with the composable middleware system provided by @qfetch/core.

Installation

npm install @qfetch/middleware-base-url

API

withBaseUrl(options)

Creates a middleware that resolves request URLs against the given base URL.

Options

  • Base URL (string | URL) (required) - The base URL to resolve requests against
    • Accepts either a string or URL instance
    • Must be a valid URL (throws TypeError if invalid)
    • Trailing slash recommended for predictable path resolution
    • Example: "https://api.example.com/v1/" or new URL("https://api.example.com/v1/")

Behavior

  • Same-origin requests - All paths (including those starting with /) are treated as relative and resolved against the base path
  • Different-origin requests - Passed through unchanged (cross-origin requests remain intact)
  • Type preservation - Input types are preserved (string→string, URL→URL, Request→Request)
  • Query parameters and fragments - Always preserved during URL resolution
  • Request properties - Method, headers, body, and other properties are preserved when reconstructing Request objects

URL Resolution Behavior

The middleware uses consistent same-origin detection across all input types:

Same-Origin Requests

All same-origin requests (strings, URLs, or Requests) have their paths treated as relative and resolved against the base path - even if they start with /:

  • "users" → appended to base path
  • "/users"also appended to base path (leading slash stripped)
  • new URL("/users", origin) → pathname appended to base path

Different-Origin Requests

Cross-origin URLs are passed through unchanged, regardless of input type:

  • "https://example.com/data" → unchanged
  • new URL("https://example.com/data") → unchanged

This consistent behavior favors practical utility: if you're using a base URL middleware, you probably want all same-origin requests to use that base path.

Important Note: Trailing Slashes

A trailing slash (/) is recommended at the end of the base URL. Without it, the URL constructor treats the final path segment as a filename and replaces it instead of appending new paths. This follows standard URL resolution behavior:

new URL("users", "https://api.example.com/v1");  // → "https://api.example.com/users"
new URL("users", "https://api.example.com/v1/"); // → "https://api.example.com/v1/users"

Usage

Basic Usage with String Inputs

import { withBaseUrl } from '@qfetch/middleware-base-url';
import { compose } from '@qfetch/core';

// Create a fetch instance with a base URL
const qfetch = compose(
  withBaseUrl('https://api.example.com/v1/')
)(fetch);

// Same-origin paths → all resolve against the base
await qfetch('users');  // → https://api.example.com/v1/users
await qfetch('/users'); // → https://api.example.com/v1/users (leading slash stripped)

// Different-origin URL → left unchanged
await qfetch('https://external.com/data'); // → https://external.com/data

Using with URL Objects

URL objects with the same origin have their paths resolved against the base:

import { withBaseUrl } from '@qfetch/middleware-base-url';

const qfetch = withBaseUrl('https://api.example.com/v1/')(fetch);

// Same origin → path resolved against base
const sameOriginUrl = new URL('/users', 'https://api.example.com');
await qfetch(sameOriginUrl); // → https://api.example.com/v1/users

// Different origin → passed through unchanged
const differentOriginUrl = new URL('https://external.com/data');
await qfetch(differentOriginUrl); // → https://external.com/data

// Query parameters and hash are preserved
const urlWithQuery = new URL('/users?page=1#top', 'https://api.example.com');
await qfetch(urlWithQuery); // → https://api.example.com/v1/users?page=1#top

Using with Request Objects

Request objects follow the same same-origin resolution logic as URL objects:

import { withBaseUrl } from '@qfetch/middleware-base-url';

const qfetch = withBaseUrl('https://api.example.com/v1/')(fetch);

// Same-origin Request → path resolved against base
const sameOriginRequest = new Request(
  new URL('/users', 'https://api.example.com'),
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: 'John Doe' })
  }
);
// → https://api.example.com/v1/users
// All other properties (method, headers, body) are preserved
await qfetch(sameOriginRequest);

// Different-origin Request → passed through unchanged
const crossOriginRequest = new Request('https://external.com/webhook', {
  method: 'POST',
  body: JSON.stringify({ event: 'user.created' })
});
await qfetch(crossOriginRequest); // → https://external.com/webhook

Important Limitations

Request Object Reconstruction Request objects are immutable according to the Fetch API specification. When resolving same-origin requests, new Request objects are created with the resolved URL. All request properties (method, headers, body, etc.) are preserved during reconstruction.

Request Body Handling Request body streams are preserved but not cloned. The body remains consumable exactly once. For requests with non-replayable body types (like ReadableStream), the body will be consumed during the first attempt and cannot be retried without providing a fresh body stream.

Notes

  • The middleware preserves input types (string→string, URL→URL, Request→Request) throughout the middleware chain
  • Same-origin detection is based on URL origin comparison (protocol + host + port)
  • Query parameters and URL fragments are always preserved during resolution
  • Different-origin requests bypass base URL resolution entirely
  • A trailing slash (/) at the end of the base URL is recommended for predictable path resolution

Standards References