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

@distilled.cloud/aws4signer

v1.0.0-rc.17

Published

Effect-native AWS Signature Version 4: sign and presign requests, or sign every request an HttpClient sends. For AWS and every S3-compatible or SigV4-signed API.

Readme

@distilled.cloud/aws4signer

Effect-native AWS Signature Version 4 (SigV4): an Effect port of aws4fetch. Sign or presign one request, or sign every request an Effect HttpClient sends.

Use it to call AWS or any SigV4 API (Cloudflare R2, MinIO, Backblaze B2, API Gateway, Lambda function URLs, ...) without the full @distilled.cloud/aws SDK. It signs byte for byte like aws4fetch; a test signs the same requests with both and compares the results. Its only dependencies are @distilled.cloud/core (for crypto) and effect. @distilled.cloud/aws uses this package and re-exports it as @distilled.cloud/aws/SigV4.

Installation

npm install @distilled.cloud/aws4signer effect

Sign every request: AwsClient

@distilled.cloud/aws4signer/AwsClient is aws4fetch's AwsClient as an HttpClient transform.

import * as AwsClient from "@distilled.cloud/aws4signer/AwsClient";
import * as Effect from "effect/Effect";
import * as FetchHttpClient from "effect/http/FetchHttpClient";
import * as HttpClient from "effect/http/HttpClient";
import * as Redacted from "effect/Redacted";

const credentials = {
  accessKeyId: process.env.R2_ACCESS_KEY_ID!,
  secretAccessKey: Redacted.make(process.env.R2_SECRET_ACCESS_KEY!),
};

const program = Effect.gen(function* () {
  // service "s3" and region "auto" come from the R2 host.
  const r2 = (yield* HttpClient.HttpClient).pipe(
    AwsClient.sign({ credentials }),
    HttpClient.retryTransient({ times: 3 }),
  );
  const res = yield* r2.get(`https://${accountId}.r2.cloudflarestorage.com/my-bucket/hello.txt`);
  return yield* res.text;
});

program.pipe(Effect.provide(FetchHttpClient.layer), Effect.runPromise);
  • AwsClient.make(options) is the context's HttpClient with sign(options) applied.
  • AwsClient.signRequest(request, options) signs one HttpClientRequest.
  • AwsClient.presign(url, { credentials, expiresIn }) returns a presigned URL.
  • credentials can be an Effect that returns the keys. It runs once per request, so it can refresh temporary credentials.
  • The signing time comes from the Effect Clock, so TestClock controls it.
  • A stream or form-data body cannot be hashed. Set the X-Amz-Content-Sha256 header (for example UNSIGNED-PAYLOAD), or the request fails with UnsignableBody. S3 signs UNSIGNED-PAYLOAD by default.

Presign a URL

import * as SigV4 from "@distilled.cloud/aws4signer";

const url = yield* SigV4.presign({
  method: "PUT",
  url: `https://${accountId}.r2.cloudflarestorage.com/uploads/avatar.png`,
  accessKeyId,
  secretAccessKey,
  expiresIn: 900,
});

Sign one request

const signed = yield* SigV4.sign({
  method: "GET",
  url: `https://${accountId}.r2.cloudflarestorage.com/${bucket}/${key}`,
  accessKeyId,
  secretAccessKey,
  service: "s3",
  region: "auto",
});
const response = yield* Effect.promise(() =>
  fetch(signed.url, { method: signed.method, headers: signed.headers }),
);

sign needs service and region. SigV4.guessScope(options) fills them from the host the way aws4fetch does (*.amazonaws.com, R2, B2, Lambda function URLs). presign and AwsClient guess on their own. The guessing lives outside sign, so a program that always passes both (the AWS SDK) does not bundle the host rules.

Options that match aws4fetch: signQuery, allHeaders, appendSessionToken, singleEncode, datetime. hashPayload also sends the body hash as X-Amz-Content-Sha256.

Errors

sign fails with a typed SigningError: InvalidSigningUrl, InvalidSigningHeaders, or CryptoError. AwsClient can also fail with UnsignableBody.