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

@oxlayer/capabilities-adapters-object-storage

v0.1.4

Published

Object storage adapter for @oxlayer/capabilities

Readme

@oxlayer/capabilities-adapters-object-storage

Object Storage adapter for AWS S3 and S3-compatible services (MinIO, R2, etc.). Provides a simplified interface for object storage with upload, download, and presigned URL generation.

Features

  • Object Storage client using Bun's native S3 API
  • Upload files (single, batch, from URL, base64)
  • Download files (as buffer, text, JSON, blob, data URL)
  • Presigned URL generation (upload and download)
  • Image upload with validation
  • Hono middleware for file uploads
  • Support for AWS S3 and S3-compatible services

Installation

bun add @oxlayer/capabilities-adapters-object-storage

Optional Dependencies

bun add @aws-sdk/client-object-storage

Usage

Basic Setup

import { createDefaultS3Client } from '@oxlayer/capabilities-adapters-object-storage';

const s3 = createDefaultS3Client({
  bucket: 'my-bucket',
  region: 'us-east-1',
  accessKeyId: 'your-key',
  secretAccessKey: 'your-secret',
});

// Upload file
await s3.upload('path/to/file.pdf', fileBuffer, {
  contentType: 'application/pdf',
  public: true,
});

// Download file
const { body } = await s3.download('path/to/file.pdf');

Environment Variables

// Uses environment variables:
// BUCKET_NAME or AWS_BUCKET=my-bucket
// AWS_REGION=us-east-1
// AWS_ACCESS_KEY_ID=your-key
// AWS_SECRET_ACCESS_KEY=your-secret
// AWS_ENDPOINT=https://s3.amazonaws.com (for S3-compatible)

Upload Operations

import { upload, uploadImage, uploadMany, uploadFromUrl, uploadBase64 } from '@oxlayer/capabilities-adapters-s3';

// Upload single file
const result = await upload('documents/report.pdf', file, {
  contentType: 'application/pdf',
  public: true,
});
console.log(result.url); // https://bucket.s3.region.amazonaws.com/documents/report.pdf

// Upload image with validation
const imageResult = await uploadImage('avatars/user123.jpg', file, {
  public: true,
});

// Upload multiple files
const results = await uploadMany('documents', [file1, file2, file3]);

// Upload from URL
const urlResult = await uploadFromUrl('downloads/image.png', 'https://example.com/image.png');

// Upload base64 data
const base64Result = await uploadBase64('assets/logo.png', base64String, {
  public: true,
});

Download Operations

import {
  download,
  downloadAsText,
  downloadAsJson,
  downloadAsBlob,
  downloadAsDataUrl,
} from '@oxlayer/capabilities-adapters-s3';

// Download as buffer
const { body } = await download('documents/report.pdf');

// Download as text
const text = await downloadAsText('documents/data.txt');

// Download as JSON
const data = await downloadAsJson('documents/config.json');

// Download as blob
const blob = await downloadAsBlob('images/photo.jpg');

// Download as data URL (base64)
const dataUrl = await downloadAsDataUrl('images/icon.png');

Presigned URLs

import { getDownloadUrl, getUploadUrl, getPresignedUrl } from '@oxlayer/capabilities-adapters-s3';

// Get download URL (expires in 1 hour)
const downloadUrl = await getDownloadUrl('documents/report.pdf', {
  expiresIn: 3600,
});

// Get upload URL (expires in 15 minutes)
const uploadUrl = await getUploadUrl('uploads/new-file.pdf', {
  expiresIn: 900,
  contentType: 'application/pdf',
});

// Get generic presigned URL
const url = await getPresignedUrl('files/data.json', 'GET', {
  expiresIn: 600,
});

Using Middleware

import { s3Middleware, fileUploadMiddleware, multiFileUploadMiddleware } from '@oxlayer/capabilities-adapters-s3';
import { Hono } from 'hono';

const app = new Hono();

// Add S3 context
app.use('/api/*', s3Middleware());

// Single file upload endpoint
app.post('/upload', fileUploadMiddleware('documents', async (file, ctx) => {
  const s3 = ctx.get('s3');
  const result = await s3.upload(`documents/${file.name}`, file);
  return result.json();
}));

// Multi-file upload endpoint
app.post('/upload/multiple', multiFileUploadMiddleware('documents', async (files, ctx) => {
  const s3 = ctx.get('s3');
  const result = await s3.uploadMany('documents', files);
  return result.json();
}));

S3-Compatible Services

// MinIO
const s3 = createDefaultS3Client({
  bucket: 'my-bucket',
  endpoint: 'http://localhost:9000',
  accessKeyId: 'minioadmin',
  secretAccessKey: 'minioadmin',
});

// Cloudflare R2
const s3 = createDefaultS3Client({
  bucket: 'my-bucket',
  endpoint: 'https://your-account.r2.cloudflarestorage.com',
  accessKeyId: 'your-r2-key',
  secretAccessKey: 'your-r2-secret',
});

API Reference

S3Client

Main client class for S3 operations.

Constructor

constructor(config: S3Config)

Config:

  • bucket - Bucket name (required)
  • region - AWS region (default: 'auto')
  • accessKeyId - AWS access key ID
  • secretAccessKey - AWS secret access key
  • endpoint - S3-compatible service endpoint
  • forcePathStyle - Use path-style URLs

Methods

upload(key: string, body: File | Blob | Buffer | string, options?): Promise<UploadResult>

Upload a file to S3.

uploadImage(key: string, file: File, options?): Promise<UploadResult>

Upload an image with validation (jpg, png, webp, gif, svg, bmp).

download(key: string, options?): Promise<DownloadResult>

Download a file from S3.

delete(key: string): Promise<void>

Delete a file from S3.

deleteMany(keys: string[]): Promise<void>

Delete multiple files.

exists(key: string): Promise<boolean>

Check if a file exists.

copy(sourceKey: string, destinationKey: string): Promise<void>

Copy a file within S3.

list(options?): Promise<ListResult>

List objects in bucket.

getMetadata(key: string): Promise<{ size: number, lastModified: Date } | null>

Get file metadata.

getPublicUrl(key: string): string

Get public URL for a key.

Helper Functions

Upload Helpers

  • upload(path, file, options?) - Upload single file
  • uploadImage(path, file, options?) - Upload image
  • uploadMany(path, files, options?) - Upload multiple files
  • uploadFromUrl(path, url, options?) - Upload from URL
  • uploadBase64(path, base64, options?) - Upload base64 data

Download Helpers

  • download(path, options?) - Download as buffer
  • downloadAsText(path) - Download as text
  • downloadAsJson<T>(path) - Download as JSON
  • downloadAsBlob(path) - Download as blob
  • downloadAsDataUrl(path) - Download as data URL

Presigned URL Helpers

  • getDownloadUrl(path, options?) - Get download URL
  • getUploadUrl(path, options?) - Get upload URL
  • getPresignedUrl(path, operation, options?) - Get presigned URL

Types

S3Config

interface S3Config {
  bucket: string;
  region?: string;
  accessKeyId?: string;
  secretAccessKey?: string;
  endpoint?: string;
  forcePathStyle?: boolean;
}

UploadOptions

interface UploadOptions {
  contentType?: string;
  public?: boolean;
}

UploadResult

interface UploadResult {
  key: string;
  url?: string;
}

DownloadResult

interface DownloadResult {
  body: ArrayBuffer;
  contentType?: string;
  contentLength: number;
}

File Paths

File paths are organized with date prefixes by default:

uploads/2024-01-12/abc123-def456.pdf
documents/2024-01-12/xyz789-abc123.pdf

Best Practices

  1. Use date prefixes: Organize files by date for better performance
  2. Set content types: Always specify correct content type
  3. Use presigned URLs: For temporary access to private files
  4. Validate uploads: Check file types and sizes
  5. Handle errors: Implement retry logic for failed uploads

License

MIT