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

@remix-run/response

v0.2.1

Published

Response helpers for the web Fetch API

Downloads

857

Readme

response

Response helpers for the web Fetch API. response provides a collection of helper functions for creating common HTTP responses with proper headers and semantics.

Basically, these are all the static response helpers we wish existed on the Response API, but don't (yet!).

Features

  • Web Standards Compliant: Built on the standard Response API, works in any JavaScript runtime (Node.js, Bun, Deno, Cloudflare Workers)
  • File Responses: Full HTTP semantics including ETags, Last-Modified, conditional requests, and Range support
  • HTML Responses: Automatic DOCTYPE prepending and proper Content-Type headers
  • Redirect Responses: Simple redirect creation with customizable status codes
  • Compress Responses: Streaming compression based on Accept-Encoding header

Installation

npm install @remix-run/response

Usage

This package provides no default export. Instead, import the specific helper you need:

import { createFileResponse } from '@remix-run/response/file'
import { createHtmlResponse } from '@remix-run/response/html'
import { createRedirectResponse } from '@remix-run/response/redirect'
import { compressResponse } from '@remix-run/response/compress'

File Responses

The createFileResponse helper creates a response for serving files with full HTTP semantics:

import { createFileResponse } from '@remix-run/response/file'
import { openFile } from '@remix-run/fs'

let file = await openFile('./public/image.jpg')
let response = await createFileResponse(file, request, {
  cacheControl: 'public, max-age=3600',
})

Features

  • Content-Type and Content-Length headers
  • ETag generation (weak or strong)
  • Last-Modified headers
  • Cache-Control headers
  • Conditional requests (If-None-Match, If-Modified-Since, If-Match, If-Unmodified-Since)
  • Range requests for partial content (206 Partial Content)
  • HEAD request support

Options

await createFileResponse(file, request, {
  // Cache-Control header value.
  // Defaults to `undefined` (no Cache-Control header).
  cacheControl: 'public, max-age=3600',

  // ETag generation strategy:
  // - 'weak': Generates weak ETags based on file size and mtime (default)
  // - 'strong': Generates strong ETags by hashing file content
  // - false: Disables ETag generation
  etag: 'weak',

  // Hash algorithm for strong ETags (Web Crypto API algorithm names).
  // Only used when etag: 'strong'.
  // Defaults to 'SHA-256'.
  digest: 'SHA-256',

  // Whether to generate Last-Modified headers.
  // Defaults to `true`.
  lastModified: true,

  // Whether to support HTTP Range requests for partial content.
  // Defaults to `true`.
  acceptRanges: true,
})

Strong ETags and Content Hashing

For assets that require strong validation (e.g., to support If-Match preconditions or If-Range with Range requests), configure strong ETag generation:

return createFileResponse(file, request, {
  etag: 'strong',
})

By default, strong ETags are generated using the Web Crypto API with the 'SHA-256' algorithm. You can customize this:

return createFileResponse(file, request, {
  etag: 'strong',
  // Specify a different hash algorithm
  digest: 'SHA-512',
})

For large files or custom hashing requirements, provide a custom digest function:

await createFileResponse(file, request, {
  etag: 'strong',
  async digest(file) {
    // Custom streaming hash for large files
    let { createHash } = await import('node:crypto')
    let hash = createHash('sha256')
    for await (let chunk of file.stream()) {
      hash.update(chunk)
    }
    return hash.digest('hex')
  },
})

HTML Responses

The createHtmlResponse helper creates HTML responses with proper Content-Type and DOCTYPE handling:

import { createHtmlResponse } from '@remix-run/response/html'

let response = createHtmlResponse('<h1>Hello, World!</h1>')
// Content-Type: text/html; charset=UTF-8
// Body: <!DOCTYPE html><h1>Hello, World!</h1>

The helper automatically prepends <!DOCTYPE html> if not already present. It works with strings, SafeHtml from @remix-run/html-template, Blobs/Files, ArrayBuffers, and ReadableStreams.

import { html } from '@remix-run/html-template'
import { createHtmlResponse } from '@remix-run/response/html'

let name = '<script>alert(1)</script>'
let response = createHtmlResponse(html`<h1>Hello, ${name}!</h1>`)
// Safely escaped HTML

Redirect Responses

The createRedirectResponse helper creates redirect responses. The main improvements over the native Response.redirect API are:

  • Accepts a relative location instead of a full URL. This isn't technically spec-compliant, but it's so widespread that many applications use relative redirects regularly without issues.
  • Accepts a ResponseInit object as the second argument, allowing you to set additional headers and status code.
import { createRedirectResponse } from '@remix-run/response/redirect'

// Default 302 redirect
let response = createRedirectResponse('/login')

// Custom status code
let response = createRedirectResponse('/new-page', 301)

// With additional headers
let response = createRedirectResponse('/dashboard', {
  status: 303,
  headers: { 'X-Redirect-Reason': 'authentication' },
})

Compress Responses

The compressResponse helper compresses a Response based on the client's Accept-Encoding header:

import { compressResponse } from '@remix-run/response/compress'

let response = new Response(JSON.stringify(data), {
  headers: { 'Content-Type': 'application/json' },
})
let compressed = await compressResponse(response, request)

Compression is automatically skipped for:

  • Responses with no Accept-Encoding header
  • Responses that are already compressed (existing Content-Encoding)
  • Responses with Cache-Control: no-transform
  • Responses with Content-Length below threshold (default: 1024 bytes)
  • Responses with range support (Accept-Ranges: bytes)
  • 206 Partial Content responses
  • HEAD requests (only headers are modified)

Options

The compressResponse helper accepts options to customize compression behavior:

await compressResponse(response, request, {
  // Minimum size in bytes to compress (only enforced if Content-Length is present).
  // Default: 1024
  threshold: 1024,

  // Which encodings the server supports for negotiation.
  // Defaults to ['br', 'gzip', 'deflate']
  encodings: ['br', 'gzip', 'deflate'],

  // node:zlib options for gzip/deflate compression.
  // For SSE responses (text/event-stream), flush: Z_SYNC_FLUSH
  // is automatically applied unless you explicitly set a flush value.
  // See: https://nodejs.org/api/zlib.html#class-options
  zlib: {
    level: 6,
  },

  // node:zlib options for Brotli compression.
  // For SSE responses (text/event-stream), flush: BROTLI_OPERATION_FLUSH
  // is automatically applied unless you explicitly set a flush value.
  // See: https://nodejs.org/api/zlib.html#class-brotlioptions
  brotli: {
    params: {
      [zlib.constants.BROTLI_PARAM_QUALITY]: 4,
    },
  },
})

Range Requests and Compression

Range requests and compression are mutually exclusive. When Accept-Ranges: bytes is present in the response headers, compressResponse will not compress the response. This is why the createFileResponse helper enables ranges only for non-compressible MIME types by default - to allow text-based assets to be compressed while still supporting resumable downloads for media files.

Related Packages

License

See LICENSE