Skip to content

arraypress/storage-r2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@arraypress/storage-r2

Cloudflare R2 native bindings adapter for @arraypress/storage. Uses the R2Bucket API directly for zero SDK overhead and maximum performance on Cloudflare Workers.

Works in Cloudflare Workers only (requires R2 bucket binding).

Installation

npm install @arraypress/storage-r2 @arraypress/storage

Usage

With Hono on Cloudflare Workers

import { Hono } from 'hono';
import { createR2Storage } from '@arraypress/storage-r2';

type Env = {
  Bindings: {
    BUCKET: R2Bucket;
  };
};

const app = new Hono<Env>();

app.post('/upload', async (c) => {
  const storage = createR2Storage({
    bucket: c.env.BUCKET,
    publicUrl: 'https://media.mystore.com',
  });

  const body = await c.req.arrayBuffer();

  const result = await storage.upload({
    key: 'uploads/photo.jpg',
    body: new Uint8Array(body),
    contentType: 'image/jpeg',
  });

  return c.json(result);
});

app.get('/download/:key{.+}', async (c) => {
  const storage = createR2Storage({ bucket: c.env.BUCKET });
  const file = await storage.download(c.req.param('key'));

  if (!file) return c.notFound();

  return new Response(file.body, {
    headers: {
      'Content-Type': file.contentType,
      'Content-Length': String(file.size),
    },
  });
});

export default app;

wrangler.toml

[[r2_buckets]]
binding = "BUCKET"
bucket_name = "my-bucket"

Content-Addressed Uploads (Deduplication)

import { createR2Storage } from '@arraypress/storage-r2';
import { contentHash, contentAddressedKey } from '@arraypress/storage';

const storage = createR2Storage({ bucket: env.BUCKET });
const hash = await contentHash(fileBuffer);
const key = contentAddressedKey(hash, 'photo.jpg', 'media/');

if (!await storage.exists(key)) {
  await storage.upload({ key, body: fileBuffer, contentType: 'image/jpeg' });
}

Multipart Uploads

const storage = createR2Storage({ bucket: env.BUCKET });

const mpu = await storage.createMultipartUpload('large-file.zip', {
  contentType: 'application/zip',
});

const part1 = await mpu.uploadPart(1, chunk1);
const part2 = await mpu.uploadPart(2, chunk2);

await mpu.complete([part1, part2]);

Signed URLs

R2 native bindings have limited presigned URL support. If you need reliable signed URLs (e.g. for direct client uploads), use @arraypress/storage-s3 with R2's S3-compatible API instead.

// May throw StorageError with code 'NOT_SUPPORTED' depending on environment
const signed = await storage.getSignedDownloadUrl({
  key: 'uploads/photo.jpg',
  expiresIn: 3600,
});

API Reference

createR2Storage(options): Storage

Creates a Storage adapter backed by Cloudflare R2 native bindings.

Options

Option Type Required Description
bucket R2Bucket Yes R2 bucket binding from wrangler.toml
publicUrl string No Public URL prefix for getPublicUrl() (e.g. 'https://media.mystore.com')

Re-exported from @arraypress/storage

  • Storage interface
  • StorageError class
  • contentHash(), contentAddressedKey(), safeDisposition() helpers
  • All type definitions

License

MIT

About

Cloudflare R2 native bindings adapter for @arraypress/storage

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors