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

secure-s3-storage

v4.0.0

Published

Validated uploads for S3-compatible object storage

Downloads

39

Readme

secure-s3-storage

npm version

English README

AWS S3, Cloudflare R2, Supabase Storage 등 S3 호환 스토리지를 위한 서버 전용 파일 업로드 라이브러리입니다.

  • provider 설정만 바꿔 같은 API를 사용합니다.
  • 파일의 확장자, Content-Type, 크기, 실제 내용을 함께 검증합니다.
  • category별 허용 확장자를 강제합니다.
  • 파일을 <category>/YYYY/MM/DD/<uuid>.<ext> 형태로 정리합니다.
  • 서버 업로드와 브라우저 직접 업로드를 모두 지원합니다.

파일 형식 위장을 차단하지만 악성코드 검사를 대신하지는 않습니다.

설치

npm install secure-s3-storage

Node.js 22 이상이 필요합니다.

설정

STORAGE_BUCKET=example-assets
STORAGE_ENDPOINT=https://0123456789abcdef0123456789abcdef.r2.cloudflarestorage.com
STORAGE_PUBLIC_BASE_URL=https://files.example.com
STORAGE_REGION=auto
STORAGE_ACCESS_KEY_ID=
STORAGE_SECRET_ACCESS_KEY=
STORAGE_SESSION_TOKEN=
STORAGE_SIGNING_SECRET=
STORAGE_FORCE_PATH_STYLE=false
import { createStorage } from "secure-s3-storage";

export const storage = createStorage({
  bucket: process.env.STORAGE_BUCKET!,
  endpoint: process.env.STORAGE_ENDPOINT!,
  publicBaseUrl: process.env.STORAGE_PUBLIC_BASE_URL!,
  region: process.env.STORAGE_REGION!,
  credentials: {
    accessKeyId: process.env.STORAGE_ACCESS_KEY_ID!,
    secretAccessKey: process.env.STORAGE_SECRET_ACCESS_KEY!,
    sessionToken: process.env.STORAGE_SESSION_TOKEN || undefined,
  },
  signingSecret: process.env.STORAGE_SIGNING_SECRET!,
  forcePathStyle: process.env.STORAGE_FORCE_PATH_STYLE === "true",
  maxFileSize: 20 * 1024 * 1024,
  categories: {
    images: ["jpg", "jpeg", "png", "apng", "webp"],
    documents: ["pdf", "txt", "md", "json", "csv", "docx", "xlsx", "pptx"],
  },
});

패키지는 환경변수를 직접 읽지 않습니다. endpoint에는 bucket을 포함하지 않은 S3 API 주소를, publicBaseUrl에는 공개 파일 URL에서 object key 앞까지의 주소를 입력합니다.

| Provider | endpoint | region | forcePathStyle | |---|---|---|---| | AWS S3 | https://s3.<REGION>.amazonaws.com | 실제 region | false | | Cloudflare R2 | https://<ACCOUNT_ID>.r2.cloudflarestorage.com | auto | false | | Supabase Storage | https://<PROJECT_REF>.storage.supabase.co/storage/v1/s3 | project region | true |

Supabase는 Storage 설정에서 S3 protocol을 활성화하고 발급된 S3 access key를 사용합니다.

signingSecret은 S3 secret access key와 다른 값이어야 하며 32자 이상이어야 합니다.

node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"

업로드 방식

| 흐름 | API | |---|---| | Server → Storage | put() | | Client → Server → Storage | 서버에서 put() | | Client → Storage | presign() → 브라우저 PUT → complete() |

Server → Storage

서버가 File을 가지고 있다면 그대로 전달합니다.

const object = await storage.put("images", file);

Buffer나 Uint8Array에는 원본 filename을 함께 전달합니다. contentType을 생략하면 확장자에서 결정합니다.

const object = await storage.put("images", buffer, {
  filename: "photo.png",
});

Client → Server → Storage

클라이언트가 보낸 multipart/form-data에서 File을 꺼내 put()에 전달합니다.

const formData = await request.formData();
const file = formData.get("file");

if (!(file instanceof File)) throw new Error("File is required");

const object = await storage.put("images", file);

두 방식 모두 서버가 파일을 받은 후 검증하여 스토리지에 저장합니다.

Client → Storage

클라이언트의 최초 업로드 요청이 서버를 거치지 않게 하려면 인증된 서버 API에서 업로드 URL을 발급합니다.

const upload = await storage.presign("images", {
  filename,
  contentType: contentType || undefined,
  size,
});

클라이언트는 반환된 URL에 파일을 직접 업로드합니다.

const response = await fetch(upload.url, {
  method: upload.method,
  headers: upload.headers,
  body: file,
});

if (!response.ok) throw new Error("Upload failed");

업로드 후 인증된 서버 API에서 파일을 검증하고 확정합니다.

const object = await storage.complete(upload.token);

파일은 _pending/<upload-id>에 임시 저장됩니다. complete()가 실제 내용을 검증한 후에만 최종 경로로 복사하며, 같은 token을 다시 전달하면 같은 결과를 반환합니다. 검증 과정에서는 임시 파일 전체를 서버 메모리로 읽으므로 maxFileSize를 서버 환경에 맞게 설정해야 합니다.

삭제와 공개 URL

await storage.remove(object.key);

const url = storage.getUrl(object.key);

getUrl()은 publicBaseUrl과 object key를 결합합니다. Private object용 signed URL은 생성하지 않습니다.

오류 처리

import { StorageError } from "secure-s3-storage";

try {
  await storage.complete(token);
} catch (error) {
  if (error instanceof StorageError) {
    console.error(error.code, error.message);
  }
}
INVALID_CONFIG      INVALID_INPUT       INVALID_TOKEN
UPLOAD_EXPIRED      UNSUPPORTED_FILE    OBJECT_NOT_FOUND
OBJECT_MISMATCH     OBJECT_CONFLICT     STORAGE_ERROR

스토리지 인증·네트워크·provider 오류의 원인은 error.cause에 보존됩니다.

브라우저 업로드에 필요한 설정

  • bucket CORS에서 애플리케이션 origin, PUT, Content-Type을 허용합니다.
  • _pending/ 객체를 자동 삭제하는 lifecycle rule을 설정합니다.
  • 공개 domain에서 /_pending/* 접근을 차단합니다.
  • presign()과 complete()을 호출하는 서버 API를 인증합니다.
  • complete() 성공 후에만 object key를 DB에 저장합니다.