UNPKG

@paschendale/r2-presigned-url

Version:

Generate presigned URLs for Cloudflare R2 storage using AWS Signature Version 4 - Compatible with Cloudflare Workers

244 lines (186 loc) 5.86 kB
# R2 Presigned URL Generator A lightweight, zero-dependency TypeScript library for generating presigned URLs for Cloudflare R2 storage using AWS Signature Version 4. Compatible with Cloudflare Workers and Node.js environments. ## Features - ✅ **Zero Dependencies** - Uses only Web Crypto API and built-in browser/Node.js APIs - ✅ **Cloudflare Workers Compatible** - No Node.js-specific dependencies - ✅ **TypeScript Support** - Full type definitions included - ✅ **AWS Signature Version 4** - Standard-compliant signature generation - ✅ **Multiple HTTP Methods** - Support for PUT, GET, and POST requests - ✅ **Comprehensive Validation** - Input validation and error handling - ✅ **Testing Utilities** - Built-in test function for debugging ## Installation ```bash npm install r2-presigned-url ``` ## Quick Start ```typescript import { generateR2PresignedUrl, R2Credentials } from 'r2-presigned-url'; const credentials: R2Credentials = { R2_ACCESS_KEY_ID: 'your-access-key', R2_SECRET_ACCESS_KEY: 'your-secret-key', R2_ACCOUNT_ID: 'your-account-id', R2_BUCKET: 'my-bucket' }; const url = await generateR2PresignedUrl( { key: 'uploads/file.jpg', contentType: 'image/jpeg', expiresIn: 3600 // 1 hour }, credentials ); console.log('Presigned URL:', url); ``` ## API Reference ### `generateR2PresignedUrl(options, credentials)` Generates a presigned URL for R2 storage operations. #### Parameters - `options` (PresignedUrlOptions): - `key` (string): The object key (path) in the R2 bucket - `contentType` (string): MIME type of the file - `expiresIn` (number): URL expiration time in seconds (max 604800 = 7 days) - `method` (optional): HTTP method - 'PUT' (default), 'GET', or 'POST' - `credentials` (R2Credentials): - `R2_ACCESS_KEY_ID` (string): Cloudflare R2 Access Key ID - `R2_SECRET_ACCESS_KEY` (string): Cloudflare R2 Secret Access Key - `R2_ACCOUNT_ID` (string): Cloudflare Account ID - `R2_BUCKET` (optional): R2 Bucket name (defaults to 'development') #### Returns - `Promise<string>`: The presigned URL ### `testPresignedUrlGeneration(credentials)` Tests the presigned URL generation with sample data. #### Parameters - `credentials` (R2Credentials): R2 credentials to test with #### Returns - `Promise<TestResult>`: Test results with success status and debug info ## Usage Examples ### Upload a File ```typescript import { generateR2PresignedUrl } from 'r2-presigned-url'; const uploadUrl = await generateR2PresignedUrl( { key: 'uploads/document.pdf', contentType: 'application/pdf', expiresIn: 1800 // 30 minutes }, credentials ); // Use the URL to upload the file const response = await fetch(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': 'application/pdf' } }); ``` ### Download a File ```typescript const downloadUrl = await generateR2PresignedUrl( { key: 'uploads/document.pdf', contentType: 'application/pdf', expiresIn: 3600, method: 'GET' }, credentials ); // Use the URL to download the file const response = await fetch(downloadUrl); const file = await response.blob(); ``` ### Testing ```typescript import { testPresignedUrlGeneration } from 'r2-presigned-url'; const result = await testPresignedUrlGeneration(credentials); if (result.success) { console.log('✅ Test passed!'); console.log('Generated URL:', result.url); console.log('Signature:', result.debug?.signature); } else { console.error('❌ Test failed:', result.error); } ``` ## Cloudflare Workers Example ```typescript // workers/index.ts import { generateR2PresignedUrl } from 'r2-presigned-url'; export default { async fetch(request: Request, env: Env): Promise<Response> { if (request.method === 'POST') { const { key, contentType } = await request.json(); const credentials = { R2_ACCESS_KEY_ID: env.R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY: env.R2_SECRET_ACCESS_KEY, R2_ACCOUNT_ID: env.R2_ACCOUNT_ID, R2_BUCKET: env.R2_BUCKET }; try { const url = await generateR2PresignedUrl( { key, contentType, expiresIn: 3600 }, credentials ); return new Response(JSON.stringify({ url }), { headers: { 'Content-Type': 'application/json' } }); } catch (error) { return new Response( JSON.stringify({ error: error.message }), { status: 400, headers: { 'Content-Type': 'application/json' } } ); } } return new Response('Method not allowed', { status: 405 }); } }; ``` ## Environment Variables For Cloudflare Workers, add these to your `wrangler.toml`: ```toml [vars] R2_ACCESS_KEY_ID = "your-access-key" R2_SECRET_ACCESS_KEY = "your-secret-key" R2_ACCOUNT_ID = "your-account-id" R2_BUCKET = "your-bucket-name" ``` ## Error Handling The library throws descriptive errors for common issues: ```typescript try { const url = await generateR2PresignedUrl(options, credentials); } catch (error) { if (error.message.includes('Missing required R2 credentials')) { // Handle missing credentials } else if (error.message.includes('Invalid parameters')) { // Handle invalid parameters } else { // Handle other errors } } ``` ## Browser Compatibility This library uses the Web Crypto API, which is supported in: - Chrome 37+ - Firefox 34+ - Safari 11+ - Edge 12+ - Node.js 15+ ## Contributing 1. Fork the repository 2. Create a feature branch 3. Make your changes 4. Add tests if applicable 5. Submit a pull request ## License MIT License - see [LICENSE](LICENSE) file for details. ## Changelog ### 1.0.0 - Initial release - AWS Signature Version 4 implementation - Cloudflare Workers compatibility - TypeScript support - Comprehensive error handling