Skip to content
Back to skills

327 Patterns A8028c56

ASecurity

```typescript const object = await env.MY_BUCKET.get(key) if (!object) return new Response('Not found', { status: 404 })

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmenttypescriptawsapi

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 327-patterns_a8028c56 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 327 Patterns A8028c56?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 327 Patterns A8028c56
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-327-patterns-a8028c56/badge)](https://www.skillsdirectory.com/skills/tools-only-327-patterns-a8028c56)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# R2 Patterns & Best Practices

## Streaming Large Files

```typescript
const object = await env.MY_BUCKET.get(key)
if (!object) return new Response('Not found', { status: 404 })

const headers = new Headers()
object.writeHttpMetadata(headers)
headers.set('etag', object.httpEtag)

return new Response(object.body, { headers })
```

## Conditional GET (304 Not Modified)

```typescript
const ifNoneMatch = request.headers.get('if-none-match')
const object = await env.MY_BUCKET.get(key, {
  onlyIf: { etagDoesNotMatch: ifNoneMatch?.replace(/"/g, '') || '' },
})

if (!object) return new Response('Not found', { status: 404 })
if (!object.body) return new Response(null, { status: 304, headers: { etag: object.httpEtag } })

return new Response(object.body, { headers: { etag: object.httpEtag } })
```

## Upload with Validation

```typescript
const key = url.pathname.slice(1)
if (!key || key.includes('..')) return new Response('Invalid key', { status: 400 })

const object = await env.MY_BUCKET.put(key, request.body, {
  httpMetadata: { contentType: request.headers.get('content-type') || 'application/octet-stream' },
  customMetadata: { uploadedAt: new Date().toISOString(), ip: request.headers.get('cf-connecting-ip') || 'unknown' },
})

return Response.json({ key: object.key, size: object.size, etag: object.httpEtag })
```

## Multipart with Progress

```typescript
const PART_SIZE = 5 * 1024 * 1024 // 5MB
const partCount = Math.ceil(file.size / PART_SIZE)
const multipart = await env.MY_BUCKET.createMultipartUpload(key, { httpMetadata: { contentType: file.type } })

const uploadedParts: R2UploadedPart[] = []
try {
  for (let i = 0; i < partCount; i++) {
    const start = i * PART_SIZE
    const part = await multipart.uploadPart(i + 1, file.slice(start, start + PART_SIZE))
    uploadedParts.push(part)
    onProgress?.(Math.round(((i + 1) / partCount) * 100))
  }
  return await multipart.complete(uploadedParts)
} catch (error) {
  await multipart.abort()
  throw error
}
```

## Batch Delete

```typescript
async function deletePrefix(prefix: string, env: Env) {
  let cursor: string | undefined
  let truncated = true

  while (truncated) {
    const listed = await env.MY_BUCKET.list({ prefix, limit: 1000, cursor })
    if (listed.objects.length > 0) {
      await env.MY_BUCKET.delete(listed.objects.map((o) => o.key))
    }
    truncated = listed.truncated
    cursor = listed.cursor
  }
}
```

## Checksum Validation & Storage Transitions

```typescript
// Upload with checksum
const hash = await crypto.subtle.digest('SHA-256', data)
await env.MY_BUCKET.put(key, data, { sha256: hash })

// Transition storage class (requires S3 SDK)
import { S3Client, CopyObjectCommand } from '@aws-sdk/client-s3'
await s3.send(
  new CopyObjectCommand({
    Bucket: 'my-bucket',
    Key: key,
    CopySource: `/my-bucket/${key}`,
    StorageClass: 'STANDARD_IA',
  }),
)
```

## Client-Side Uploads (Presigned URLs)

```typescript
import { S3Client } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
import { PutObjectCommand } from '@aws-sdk/client-s3'

// Worker: Generate presigned upload URL
const s3 = new S3Client({
  region: 'auto',
  endpoint: `https://${env.ACCOUNT_ID}.r2.cloudflarestorage.com`,
  credentials: { accessKeyId: env.R2_ACCESS_KEY_ID, secretAccessKey: env.R2_SECRET_ACCESS_KEY },
})

const url = await getSignedUrl(s3, new PutObjectCommand({ Bucket: 'my-bucket', Key: key }), { expiresIn: 3600 })
return Response.json({ uploadUrl: url })

// Client: Upload directly
const { uploadUrl } = await fetch('/api/upload-url').then((r) => r.json())
await fetch(uploadUrl, { method: 'PUT', body: file })
```

## Caching with Cache API

```typescript
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const cache = caches.default
    const url = new URL(request.url)
    const cacheKey = new Request(url.toString(), request)

    // Check cache first
    let response = await cache.match(cacheKey)
    if (response) return response

    // Fetch from R2
    const key = url.pathname.slice(1)
    const object = await env.MY_BUCKET.get(key)
    if (!object) return new Response('Not found', { status: 404 })

    const headers = new Headers()
    object.writeHttpMetadata(headers)
    headers.set('etag', object.httpEtag)
    headers.set('cache-control', 'public, max-age=31536000, immutable')

    response = new Response(object.body, { headers })

    // Cache for subsequent requests
    ctx.waitUntil(cache.put(cacheKey, response.clone()))

    return response
  },
}
```

## Public Bucket with Custom Domain

```typescript
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // CORS preflight
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        headers: {
          'access-control-allow-origin': '*',
          'access-control-allow-methods': 'GET, HEAD',
          'access-control-max-age': '86400',
        },
      })
    }

    const key = new URL(request.url).pathname.slice(1)
    if (!key) return Response.redirect('/index.html', 302)

    const object = await env.MY_BUCKET.get(key)
    if (!object) return new Response('Not found', { status: 404 })

    const headers = new Headers()
    object.writeHttpMetadata(headers)
    headers.set('etag', object.httpEtag)
    headers.set('access-control-allow-origin', '*')
    headers.set('cache-control', 'public, max-age=31536000, immutable')

    return new Response(object.body, { headers })
  },
}
```

## r2.dev Public URLs

Enable r2.dev in dashboard for simple public access: `https://pub-${hashId}.r2.dev/${key}`  
Or add custom domain via dashboard: `https://files.example.com/${key}`

**Limitations:** No auth, bucket-level CORS, no cache override.

Files in this skill

  • README.md1 KB
  • skill.md5.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.