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

@freshpointcz/fresh-s3

v0.0.1

Published

Reusable, strongly-typed S3 abstraction

Readme

@freshpointcz/fresh-s3 🪣

A strongly-typed, fail-loud S3 abstraction built for the internal microservices ecosystem.

This package wraps the AWS SDK v3 with a tiny, opinionated API for uploading, downloading, and listing objects. It works against Hetzner Object Storage, AWS S3, MinIO, and any S3-compatible provider — a service just imports the client, points it at a bucket, and calls a handful of methods.

✨ Key Features

  • Fail-Loud By Design: Every operation either returns a typed result or throws a concrete S3Error subclass. Nothing is ever silently swallowed — no null, no false, no quiet catch.
  • Stream-First Uploads: Uploads always use multipart streaming via lib-storage, handling objects of any size without buffering them in memory.
  • Complete Listings: listMany transparently follows pagination, so results are complete regardless of object count (no silent 1000-object cap).
  • Typed Errors: Seven discriminated error classes (S3NotFoundError, S3UploadError, …) carry the original cause and the S3 HTTP status.
  • Domain-Agnostic Folders: The S3Folder builder validates and composes keys without the package ever knowing your concrete folders.
  • One-Line Setup: FreshS3Client.fromEnv() reads canonical S3_* variables — no boilerplate in the service.

📦 Installation

This package declares the AWS SDK packages as peer dependencies, so each service installs the versions it already uses.

npm install @freshpointcz/fresh-s3 \
            @aws-sdk/client-s3 \
            @aws-sdk/lib-storage \
            @aws-sdk/s3-request-presigner

⚙️ Configuration

The client needs an endpoint, region, credentials, and a bucket. Provide them explicitly, or read the canonical environment variables.

| Variable | Required | Description | | ---------------------- | -------- | -------------------------------------------------------- | | S3_ENDPOINT | yes | Full endpoint URL, e.g. https://fsn1.your-objectstorage.com | | S3_REGION | yes | Region, e.g. fsn1 | | S3_ACCESS_KEY_ID | yes | Access key ID | | S3_SECRET_ACCESS_KEY | yes | Secret access key | | S3_BUCKET | yes | Target bucket | | S3_FORCE_PATH_STYLE | no | "true" for MinIO / local path-style storage; otherwise omit |

Per-service credentials: each service gets its own access keys, configured through that service's own environment — never a shared key.

A missing or blank required field throws S3ConfigError immediately when the client is constructed — misconfiguration never reaches the network.

🚀 Quick Start

import { FreshS3Client, S3Folder } from "@freshpointcz/fresh-s3";
import { Readable } from "stream";

// One line of setup — reads the S3_* environment variables.
const s3 = FreshS3Client.fromEnv();

// Define your folders once (the package stays domain-agnostic).
const PRODUCT = new S3Folder("common", "product");

// Upload (always a stream — wrap a Buffer with Readable.from).
const { key, etag } = await s3.upload(
    PRODUCT.key("1778_abc.jpg"),
    Readable.from(buffer),
    { contentType: "image/jpeg", acl: "public-read" }
);

// Download as a stream.
const stream = await s3.download(key);

// Presigned, time-limited read URL.
const url = await s3.getSignedUrl(key, 3600);

Prefer explicit config over environment variables? Pass it to the constructor:

const s3 = new FreshS3Client({
    endpoint: "https://fsn1.your-objectstorage.com",
    region: "fsn1",
    accessKeyId: process.env.S3_ACCESS_KEY_ID!,
    secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
    bucket: "fresh-media-prod",
});

📚 API

| Method | Returns | Notes | | --------------------------------------- | ------------------------ | ------------------------------------------------------------ | | upload(key, body, options?) | S3UploadResult | Multipart stream upload. Body is always a Readable. | | download(key) | Readable | Throws S3NotFoundError if the object is missing. | | listOne(key) | S3ObjectMeta | Metadata only (HEAD). Throws S3NotFoundError if missing. | | listMany(prefix) | S3ObjectMeta[] | Auto-paginates; complete regardless of count. Newest first. | | delete(key) | void | No-op on S3 for a missing key. | | getSignedUrl(key, expiresInSeconds?) | string | Default lifetime 3600s. | | checkConnection() | S3ConnectionStatus | Status report — never throws for an unreachable bucket. | | verifyConnection() | void | Fail-loud startup variant — throws S3ConnectionError. |

🗂️ Folders

S3Folder builds and validates object keys. It knows the concept of a folder, not your concrete folders — you define those:

const PRODUCT = new S3Folder("common", "product");
PRODUCT.prefix;            // "common/product"
PRODUCT.key("foto.jpg");   // "common/product/foto.jpg"

const THUMBS = PRODUCT.child("thumbnails"); // "common/product/thumbnails"

Segments are validated on construction: no empty values, no slashes inside a segment, no surrounding whitespace, no ./.. traversal. An invalid segment throws S3ConfigError.

🛑 Error Handling

The library is fail-loud: every method either returns a typed result or throws. All errors extend the abstract S3Error and carry a code, the originating cause, and the S3 httpStatusCode when available.

| Error | code | Thrown when | | -------------------- | ------------- | -------------------------------------------- | | S3ConfigError | config | Config or folder segment is invalid | | S3ConnectionError | connection | Bucket unreachable / credentials rejected | | S3UploadError | upload | Upload fails | | S3DownloadError | download | Download or URL signing fails | | S3NotFoundError | not-found | Object does not exist | | S3DeleteError | delete | Delete request fails | | S3ListError | list | Listing or metadata read fails |

import { S3NotFoundError } from "@freshpointcz/fresh-s3";

try {
    await s3.download("missing/key.jpg");
} catch (err) {
    if (err instanceof S3NotFoundError) {
        // handle missing object
    }
    throw err;
}

Note: Since fresh-s3 is transport-agnostic (it may run in a CRON job or CLI, not just an HTTP controller), it does not depend on fresh-core and does not throw ApiError. In an HTTP context, map an S3Error onto your service's own error type in the controller.

🩺 Health Checks

// Health endpoint — reports status, never throws for an unreachable bucket.
const status = await s3.checkConnection();
// → { ok: true } | { ok: false, reason: "..." }

// Startup — fail-loud, aborts boot if S3 is unreachable.
await s3.verifyConnection(); // throws S3ConnectionError